}
}
+void file_dump_open_table(void)
+{
+ int count=0;
+ files_struct *fsp;
+
+ for (fsp=Files;fsp;fsp=fsp->next,count++) {
+ DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, fileid = %lu, dev = %x, inode = %.0f\n",
+ count, fsp->fnum, fsp->fsp_name, fsp->fd, (unsigned long)fsp->file_id,
+ (unsigned int)fsp->dev, (double)fsp->inode ));
+ }
+}
+
/****************************************************************************
Find a fsp given a file descriptor.
****************************************************************************/
restore_case_semantics(file_attributes);
if(!fsp) {
- set_bad_path_error(errno, bad_path);
END_PROFILE(SMBntcreateX);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
} else {
/*
if(!fsp) {
restore_case_semantics(file_attributes);
- set_bad_path_error(errno, bad_path);
END_PROFILE(SMBntcreateX);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
} else {
restore_case_semantics(file_attributes);
- set_bad_path_error(errno, bad_path);
END_PROFILE(SMBntcreateX);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
}
}
if(!fsp) {
restore_case_semantics(file_attributes);
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
} else {
if(!fsp) {
restore_case_semantics(file_attributes);
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
} else {
restore_case_semantics(file_attributes);
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
}
}
if (!ok) {
- set_bad_path_error(errno, bad_path);
END_PROFILE(SMBgetatr);
- return(UNIXERROR(ERRDOS,ERRbadfile));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadfile);
}
outsize = set_message(outbuf,10,0,True);
ok = set_filetime(conn,fname,mtime);
if (!ok) {
- set_bad_path_error(errno, bad_path);
END_PROFILE(SMBsetatr);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
}
outsize = set_message(outbuf,0,0,True);
dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
if (dptr_num < 0) {
if(dptr_num == -2) {
- set_bad_path_error(errno, bad_path);
END_PROFILE(SMBsearch);
- return (UNIXERROR(ERRDOS,ERRnofids));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnofids);
}
END_PROFILE(SMBsearch);
return ERROR_DOS(ERRDOS,ERRnofids);
unixmode, oplock_request,&rmode,NULL);
if (!fsp) {
- set_bad_path_error(errno, bad_path);
END_PROFILE(SMBopen);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
}
size = sbuf.st_size;
oplock_request, &rmode,&smb_action);
if (!fsp) {
- set_bad_path_error(errno, bad_path);
END_PROFILE(SMBopenX);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
}
size = sbuf.st_size;
ofun, unixmode, oplock_request, NULL, NULL);
if (!fsp) {
- set_bad_path_error(errno, bad_path);
END_PROFILE(SMBcreate);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
}
outsize = set_message(outbuf,1,0,True);
close(tmpfd);
if (!fsp) {
- set_bad_path_error(errno, bad_path);
END_PROFILE(SMBctemp);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
}
outsize = set_message(outbuf,1,0,True);
/* Can't delete a directory. */
if (fmode & aDIR)
return NT_STATUS_FILE_IS_A_DIRECTORY;
+#if 0 /* JRATEST */
else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
return NT_STATUS_OBJECT_NAME_INVALID;
+#endif /* JRATEST */
if (!lp_delete_readonly(SNUM(conn))) {
if (fmode & aRONLY)
ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));
if (ret == -1) {
- NTSTATUS nterr = set_bad_path_error(errno, bad_path);
+ NTSTATUS nterr = NT_STATUS_OK;
+ if(errno == ENOENT) {
+ unix_ERR_class = ERRDOS;
+ if (bad_path) {
+ unix_ERR_code = ERRbadpath;
+ nterr = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ } else {
+ unix_ERR_code = ERRbadfile;
+ nterr = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ }
if (!NT_STATUS_IS_OK(nterr))
return nterr;
return map_nt_error_from_unix(errno);
}
if (!ok) {
- set_bad_path_error(errno, bad_path);
END_PROFILE(SMBrmdir);
- return(UNIXERROR(ERRDOS,ERRbadpath));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRbadpath);
}
outsize = set_message(outbuf,0,0,True);
return(True);
}
+/****************************************************************************
+ Ensure open files have their names updates.
+****************************************************************************/
+
+static void rename_open_files(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode, char *newname)
+{
+ files_struct *fsp;
+ BOOL did_rename = False;
+
+ for(fsp = file_find_di_first(dev, inode); fsp; fsp = file_find_di_next(fsp)) {
+ DEBUG(10,("rename_open_files: renaming file fnum %d (dev = %x, inode = %.0f) from %s -> %s\n",
+ fsp->fnum, (unsigned int)fsp->dev, (double)fsp->inode,
+ fsp->fsp_name, newname ));
+ string_set(&fsp->fsp_name, newname);
+ did_rename = True;
+ }
+
+ if (!did_rename)
+ DEBUG(10,("rename_open_files: no open files on dev %x, inode %.0f for %s\n",
+ (unsigned int)dev, (double)inode, newname ));
+}
+
+/****************************************************************************
+ Rename an open file - given an fsp.
+****************************************************************************/
+
+NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *newname, BOOL replace_if_exists)
+{
+ SMB_STRUCT_STAT sbuf;
+ BOOL bad_path = False;
+ pstring newname_last_component;
+ NTSTATUS error = NT_STATUS_OK;
+ BOOL dest_exists;
+
+ ZERO_STRUCT(sbuf);
+ unix_convert(newname,conn,newname_last_component,&bad_path,&sbuf);
+
+ /* Ensure newname contains a '/' */
+ if(strrchr_m(newname,'/') == 0) {
+ pstring tmpstr;
+
+ pstrcpy(tmpstr, "./");
+ pstrcat(tmpstr, newname);
+ pstrcpy(newname, tmpstr);
+ }
+
+ /*
+ * Check for special case with case preserving and not
+ * case sensitive. If the old last component differs from the original
+ * last component only by case, then we should allow
+ * the rename (user is trying to change the case of the
+ * filename).
+ */
+
+ if((case_sensitive == False) && (case_preserve == True) &&
+ strequal(newname, fsp->fsp_name)) {
+ char *p;
+ pstring newname_modified_last_component;
+
+ /*
+ * Get the last component of the modified name.
+ * Note that we guarantee that newname contains a '/'
+ * character above.
+ */
+ p = strrchr_m(newname,'/');
+ pstrcpy(newname_modified_last_component,p+1);
+
+ if(strcsequal(newname_modified_last_component,
+ newname_last_component) == False) {
+ /*
+ * Replace the modified last component with
+ * the original.
+ */
+ pstrcpy(p+1, newname_last_component);
+ }
+ }
+
+ /*
+ * If the src and dest names are identical - including case,
+ * don't do the rename, just return success.
+ */
+
+ if (strcsequal(fsp->fsp_name, newname)) {
+ DEBUG(3,("rename_internals_fsp: identical names in rename %s - returning success\n",
+ newname));
+ return NT_STATUS_OK;
+ }
+
+ dest_exists = vfs_object_exist(conn,newname,NULL);
+
+ if(!replace_if_exists && dest_exists) {
+ DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n",
+ fsp->fsp_name,newname));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ error = can_rename(newname,conn,&sbuf);
+
+ if (dest_exists && !NT_STATUS_IS_OK(error)) {
+ DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
+ nt_errstr(error), fsp->fsp_name,newname));
+ if (NT_STATUS_EQUAL(error,NT_STATUS_SHARING_VIOLATION))
+ error = NT_STATUS_ACCESS_DENIED;
+ return error;
+ }
+
+ if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
+ DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n",
+ fsp->fsp_name,newname));
+ rename_open_files(conn, fsp->dev, fsp->inode, newname);
+ return NT_STATUS_OK;
+ }
+
+ if (errno == ENOTDIR || errno == EISDIR)
+ error = NT_STATUS_OBJECT_NAME_COLLISION;
+ else
+ error = map_nt_error_from_unix(errno);
+
+ DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
+ nt_errstr(error), fsp->fsp_name,newname));
+
+ return error;
+}
+
/****************************************************************************
The guts of the rename command, split out so it may be called by the NT SMB
code.
*directory = *mask = 0;
+ ZERO_STRUCT(sbuf1);
+ ZERO_STRUCT(sbuf2);
rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
unix_convert(newname,conn,newname_last_component,&bad_path2,&sbuf2);
*/
if (strcsequal(directory, newname)) {
+ rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname);
DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory));
return NT_STATUS_OK;
}
if(SMB_VFS_RENAME(conn,directory, newname) == 0) {
DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n",
directory,newname));
+ rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname);
return NT_STATUS_OK;
}
continue;
}
- if (!SMB_VFS_RENAME(conn,fname,destname))
+ if (!SMB_VFS_RENAME(conn,fname,destname)) {
+ rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname);
count++;
+ }
DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
}
CloseDir(dirptr);
/*
Unix SMB/CIFS implementation.
SMB transaction2 handling
- Copyright (C) Jeremy Allison 1994-2001
+ Copyright (C) Jeremy Allison 1994-2003
Copyright (C) Stefan (metze) Metzmacher 2003
Extensively modified by Andrew Tridgell, 1995
unix_convert(fname,conn,0,&bad_path,&sbuf);
if (!check_name(fname,conn)) {
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
unixmode = unix_mode(conn,open_attr | aARCH, fname);
oplock_request, &rmode,&smb_action);
if (!fsp) {
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
size = get_file_size(sbuf);
}
/****************************************************************************
-checks for SMB_TIME_NO_CHANGE and if not found
-calls interpret_long_date
+ Checks for SMB_TIME_NO_CHANGE and if not found calls interpret_long_date.
****************************************************************************/
+
time_t interpret_long_unix_date(char *p)
{
DEBUG(1,("interpret_long_unix_date\n"));
unix_convert(directory,conn,0,&bad_path,&sbuf);
if(!check_name(directory,conn)) {
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRbadpath));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
p = strrchr_m(directory,'/');
* Utility function to set bad path error.
****************************************************************************/
-NTSTATUS set_bad_path_error(int err, BOOL bad_path)
+int set_bad_path_error(int err, BOOL bad_path, char *outbuf, int def_class, uint32 def_code)
{
- if((err == ENOENT) && bad_path) {
+ DEBUG(10,("set_bad_path_error: err = %dm bad_path = %d\n",
+ err, (int)bad_path ));
+
+ if(err == ENOENT) {
unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ if (bad_path) {
+ unix_ERR_code = ERRbadpath;
+ return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
+ } else {
+ unix_ERR_code = ERRbadfile;
+ return ERROR_NT(NT_STATUS_OBJECT_NAME_NOT_FOUND);
+ }
}
- return NT_STATUS_OK;
+ return UNIXERROR(def_class,def_code);
}
/****************************************************************************
unix_convert(fname,conn,0,&bad_path,&sbuf);
if (!check_name(fname,conn)) {
DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed for fake_file(%s)\n",fname,strerror(errno)));
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRbadpath));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
} else if(fsp && (fsp->is_directory || fsp->fd == -1)) {
unix_convert(fname,conn,0,&bad_path,&sbuf);
if (!check_name(fname,conn)) {
DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRbadpath));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
if (INFO_LEVEL_IS_UNIX(info_level)) {
/* Always do lstat for UNIX calls. */
if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRbadpath));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
} else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) {
DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRbadpath));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
delete_pending = fsp->directory_delete_on_close;
unix_convert(fname,conn,0,&bad_path,&sbuf);
if (!check_name(fname,conn)) {
DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRbadpath));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
if (INFO_LEVEL_IS_UNIX(info_level)) {
/* Always do lstat for UNIX calls. */
if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRbadpath));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
} else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) {
DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRbadpath));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
}
if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions())
return ERROR_DOS(ERRDOS,ERRunknownlevel);
- DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n",
- fname,info_level,tran_call,total_data));
+ DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n",
+ fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data));
p = strrchr_m(fname,'/');
if (!p)
unix_convert(fname,conn,0,&bad_path,&sbuf);
if (!check_name(fname,conn) || (!VALID_STAT(sbuf))) {
DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRbadpath));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
} else if (fsp && fsp->print_file) {
/*
srvstr_pull(inbuf, fname, ¶ms[6], sizeof(fname), -1, STR_TERMINATE);
unix_convert(fname,conn,0,&bad_path,&sbuf);
if(!check_name(fname, conn)) {
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRbadpath));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
}
/*
if(!VALID_STAT(sbuf) && !INFO_LEVEL_IS_UNIX(info_level)) {
DEBUG(3,("call_trans2setfilepathinfo: stat of %s failed (%s)\n", fname, strerror(errno)));
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRbadpath));
+ return ERROR_NT(NT_STATUS_OBJECT_NAME_NOT_FOUND);
}
}
if (VALID_STAT(sbuf))
unixmode = sbuf.st_mode;
- DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n",
- tran_call,fname,info_level,total_data));
+ DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d totdata=%d\n",
+ tran_call,fname, fsp ? fsp->fnum : -1, info_level,total_data));
/* Realloc the parameter and data sizes */
params = Realloc(*pparams,2);
case SMB_FILE_DISPOSITION_INFORMATION:
case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
{
- BOOL delete_on_close = (CVAL(pdata,0) ? True : False);
+ BOOL delete_on_close;
NTSTATUS status;
if (total_data < 1)
return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+ delete_on_close = (CVAL(pdata,0) ? True : False);
+
/* Just ignore this set on a path. */
if (tran_call != TRANSACT2_SETFILEINFO)
break;
return(-1);
}
+ case SMB_FILE_RENAME_INFORMATION:
+ {
+ BOOL overwrite;
+ uint32 root_fid;
+ uint32 len;
+ pstring newname;
+ pstring base_name;
+ char *p;
+ NTSTATUS status;
+
+ if (total_data < 12)
+ return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+ overwrite = (CVAL(pdata,0) ? True : False);
+ root_fid = IVAL(pdata,4);
+ len = IVAL(pdata,8);
+ srvstr_pull(inbuf, newname, &pdata[12], sizeof(newname), len, 0);
+
+ /* Check the new name has no '\' characters. */
+ if (strchr_m(newname, '\\') || strchr_m(newname, '/'))
+ return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
+
+ RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
+
+ /* Create the base directory. */
+ pstrcpy(base_name, fname);
+ p = strrchr_m(base_name, '/');
+ if (p)
+ *p = '\0';
+ /* Append the new name. */
+ pstrcat(base_name, "/");
+ pstrcat(base_name, newname);
+
+ if (fsp) {
+ DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
+ fsp->fnum, fsp->fsp_name, base_name ));
+ status = rename_internals_fsp(conn, fsp, base_name, overwrite);
+ } else {
+ DEBUG(10,("call_trans2setfilepathinfo: SMB_FILE_RENAME_INFORMATION %s -> %s\n",
+ fname, newname ));
+ status = rename_internals(conn, fname, base_name, overwrite);
+ }
+ if (!NT_STATUS_IS_OK(status))
+ return ERROR_NT(status);
+ process_pending_change_notify_queue((time_t)0);
+ SSVAL(params,0,0);
+ send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+ return(-1);
+ }
default:
return ERROR_DOS(ERRDOS,ERRunknownlevel);
}
if(ret < 0) {
DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
- set_bad_path_error(errno, bad_path);
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
}
/* Realloc the parameter and data sizes */