From 3a052c9e0a62c1f8ddf4c2e509cff52a4d157d21 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Sat, 16 Aug 2003 02:34:03 +0000 Subject: Implemented the level 1010 NT rename level. Many fixes for Samba4 test correctness. Jeremy. (This used to be commit f57429befa43d63ed9a6e19b854e22fd4151db40) --- source3/smbd/files.c | 12 ++++ source3/smbd/nttrans.c | 18 ++---- source3/smbd/reply.c | 170 +++++++++++++++++++++++++++++++++++++++++++------ source3/smbd/trans2.c | 127 ++++++++++++++++++++++++------------ 4 files changed, 256 insertions(+), 71 deletions(-) (limited to 'source3') diff --git a/source3/smbd/files.c b/source3/smbd/files.c index f0fd6b7a73..186fa96d7d 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -200,6 +200,18 @@ void file_close_user(int vuid) } } +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. ****************************************************************************/ diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 7a58e83877..f8bd3ae15f 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -762,9 +762,8 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib 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 { /* @@ -838,16 +837,14 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib 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); } } } @@ -1279,8 +1276,7 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o 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 { @@ -1312,13 +1308,11 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o 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); } } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 35d07d5bf7..34200b0cab 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -497,9 +497,8 @@ int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size } 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); @@ -560,9 +559,8 @@ int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size 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); @@ -723,9 +721,8 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size 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); @@ -890,9 +887,8 @@ int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, 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; @@ -978,9 +974,8 @@ int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt 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; @@ -1102,9 +1097,8 @@ int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_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); @@ -1171,9 +1165,8 @@ int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, 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); @@ -1268,8 +1261,10 @@ static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype) /* 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) @@ -2885,7 +2880,17 @@ NTSTATUS mkdir_internal(connection_struct *conn, pstring directory) 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); @@ -3080,9 +3085,8 @@ int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, } 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); @@ -3165,6 +3169,130 @@ static BOOL resolve_wildcards(const char *name1, char *name2) 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. @@ -3186,6 +3314,8 @@ NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BO *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); @@ -3326,6 +3456,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", */ 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; } @@ -3339,6 +3470,7 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", 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; } @@ -3403,8 +3535,10 @@ directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", 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); diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 3716378b37..f56d2dff22 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1,7 +1,7 @@ /* 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 @@ -261,8 +261,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i 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); @@ -271,8 +270,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i 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); @@ -441,9 +439,9 @@ static mode_t unix_perms_from_wire( connection_struct *conn, SMB_STRUCT_STAT *ps } /**************************************************************************** -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")); @@ -910,8 +908,7 @@ close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\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,'/'); @@ -1716,14 +1713,22 @@ static int call_trans2setfsinfo(connection_struct *conn, * 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); } /**************************************************************************** @@ -1778,8 +1783,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, 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)) { @@ -1792,21 +1796,18 @@ static int call_trans2qfilepathinfo(connection_struct *conn, 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; @@ -1840,29 +1841,26 @@ static int call_trans2qfilepathinfo(connection_struct *conn, 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) @@ -2422,8 +2420,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, 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) { /* @@ -2462,8 +2459,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, 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); } /* @@ -2472,8 +2468,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn, 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); } } @@ -2486,8 +2481,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn, 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); @@ -2679,12 +2674,14 @@ static int call_trans2setfilepathinfo(connection_struct *conn, 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; @@ -2905,6 +2902,55 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n", 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); } @@ -3056,8 +3102,7 @@ static int call_trans2mkdir(connection_struct *conn, 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 */ -- cgit