diff options
author | Jeremy Allison <jra@samba.org> | 2002-01-04 21:11:35 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2002-01-04 21:11:35 +0000 |
commit | eb61d92ca7053bef9142a29f296aae695c47db33 (patch) | |
tree | ace319cdf0210116ae07067c3edbbb1e6e2ddf1c /source3/smbd/reply.c | |
parent | 8942e906f0b3d02a94a3bd0411d3d11ac4af5873 (diff) | |
download | samba-eb61d92ca7053bef9142a29f296aae695c47db33.tar.gz samba-eb61d92ca7053bef9142a29f296aae695c47db33.tar.xz samba-eb61d92ca7053bef9142a29f296aae695c47db33.zip |
Re-wrote the guts of the rename_internals code to cope with a reported
bug (renaming name -> name was failing, on W2K it succeeds). Simplified
the common case, did a lot of work to ensure NT error codes are correctly
reported back to client.
Jeremy.
(This used to be commit e6b27f3d8069ae304baaebe09341c58d46b05fe4)
Diffstat (limited to 'source3/smbd/reply.c')
-rw-r--r-- | source3/smbd/reply.c | 117 |
1 files changed, 80 insertions, 37 deletions
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 0e7eca3ac2f..9e6f8d24c21 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -2952,26 +2952,26 @@ static BOOL resolve_wildcards(char *name1,char *name2) } /******************************************************************* -check if a user is allowed to rename a file + Check if a user is allowed to rename a file. ********************************************************************/ -static BOOL can_rename(char *fname,connection_struct *conn) + +static NTSTATUS can_rename(char *fname,connection_struct *conn) { - SMB_STRUCT_STAT sbuf; + if (!CAN_WRITE(conn)) + return NT_STATUS_ACCESS_DENIED; - if (!CAN_WRITE(conn)) return(False); + if (!check_file_sharing(conn,fname,True)) + return NT_STATUS_SHARING_VIOLATION; - if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0) return(False); - if (!check_file_sharing(conn,fname,True)) return(False); - return(True); + return NT_STATUS_OK; } /**************************************************************************** The guts of the rename command, split out so it may be called by the NT SMB code. ****************************************************************************/ -NTSTATUS rename_internals(connection_struct *conn, - char *name, - char *newname, BOOL replace_if_exists) + +NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BOOL replace_if_exists) { pstring directory; pstring mask; @@ -2982,7 +2982,6 @@ NTSTATUS rename_internals(connection_struct *conn, BOOL bad_path2 = False; int count=0; NTSTATUS error = NT_STATUS_OK; - BOOL exists=False; BOOL rc = True; SMB_STRUCT_STAT sbuf1, sbuf2; @@ -3056,7 +3055,8 @@ NTSTATUS rename_internals(connection_struct *conn, pstrcpy(newname, tmpstr); } - DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", + DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \ +directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", case_sensitive, case_preserve, short_case_preserve, directory, newname, newname_last_component, is_short_name)); @@ -3093,34 +3093,76 @@ NTSTATUS rename_internals(connection_struct *conn, pstrcpy(p+1, newname_last_component); } } - - if(replace_if_exists) { - /* - * NT SMB specific flag - rename can overwrite - * file with the same name so don't check for - * vfs_file_exist(). - */ + + resolve_wildcards(directory,newname); + + /* + * The source object must exist. + */ - if(resolve_wildcards(directory,newname) && - can_rename(directory,conn) && - conn->vfs_ops.rename(conn,directory,newname) == 0) - count++; - } else { - if (resolve_wildcards(directory,newname) && - can_rename(directory,conn) && - !vfs_file_exist(conn,newname,NULL) && - conn->vfs_ops.rename(conn,directory,newname) == 0) - count++; + if (!vfs_object_exist(conn, directory, NULL)) { + DEBUG(3,("rename_internals: source doesn't exist doing rename %s -> %s\n", + directory,newname)); + + if (errno == ENOTDIR || errno == EISDIR || errno == ENOENT) { + /* + * Must return different errors depending on whether the parent + * directory existed or not. + */ + + p = strrchr_m(directory, '/'); + if (!p) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + *p = '\0'; + if (vfs_object_exist(conn, directory, NULL)) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } + error = map_nt_error_from_unix(errno); + DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", + get_nt_error_msg(error), directory,newname)); + + return error; } - DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed", - directory,newname)); - - if (!count) exists = vfs_file_exist(conn,directory,NULL); - if (!count && exists && vfs_file_exist(conn,newname,NULL)) { - exists = True; - error = NT_STATUS_OBJECT_NAME_COLLISION; + error = can_rename(directory,conn); + + if (!NT_STATUS_IS_OK(error)) { + DEBUG(3,("rename_internals: Error %s rename %s -> %s\n", + get_nt_error_msg(error), directory,newname)); + } + + /* + * If the src and dest names are identical - including case, + * don't do the rename, just return success. + */ + + if (strcsequal(directory, newname)) { + DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory)); + return NT_STATUS_OK; } + + if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) { + DEBUG(3,("rename_internals: dest exists doing rename %s -> %s\n", + directory,newname)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + if(conn->vfs_ops.rename(conn,directory, newname) == 0) { + DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n", + directory,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: Error %s rename %s -> %s\n", + get_nt_error_msg(error), directory,newname)); + + return error; } else { /* * Wildcards - process each file that matches. @@ -3148,7 +3190,8 @@ NTSTATUS rename_internals(connection_struct *conn, error = NT_STATUS_ACCESS_DENIED; slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname); - if (!can_rename(fname,conn)) { + error = can_rename(fname,conn); + if (!NT_STATUS_IS_OK(error)) { DEBUG(6,("rename %s refused\n", fname)); continue; } |