diff options
Diffstat (limited to 'source3/smbd/reply.c')
-rw-r--r-- | source3/smbd/reply.c | 170 |
1 files changed, 152 insertions, 18 deletions
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); @@ -3166,6 +3170,130 @@ static BOOL resolve_wildcards(const char *name1, char *name2) } /**************************************************************************** + 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); |