1
0
mirror of https://github.com/samba-team/samba.git synced 2025-09-23 01:44:20 +03:00

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 e6b27f3d80)
This commit is contained in:
Jeremy Allison
2002-01-04 21:11:35 +00:00
parent 8942e906f0
commit eb61d92ca7
3 changed files with 102 additions and 41 deletions

View File

@@ -1454,7 +1454,8 @@ static int call_nt_transact_rename(connection_struct *conn,
status = rename_internals(conn, fsp->fsp_name, status = rename_internals(conn, fsp->fsp_name,
new_name, replace_if_exists); new_name, replace_if_exists);
if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status); if (!NT_STATUS_IS_OK(status))
return ERROR_NT(status);
/* /*
* Rename was successful. * Rename was successful.

View File

@@ -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); return NT_STATUS_OK;
if (!check_file_sharing(conn,fname,True)) return(False);
return(True);
} }
/**************************************************************************** /****************************************************************************
The guts of the rename command, split out so it may be called by the NT SMB The guts of the rename command, split out so it may be called by the NT SMB
code. code.
****************************************************************************/ ****************************************************************************/
NTSTATUS rename_internals(connection_struct *conn,
char *name, NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BOOL replace_if_exists)
char *newname, BOOL replace_if_exists)
{ {
pstring directory; pstring directory;
pstring mask; pstring mask;
@@ -2982,7 +2982,6 @@ NTSTATUS rename_internals(connection_struct *conn,
BOOL bad_path2 = False; BOOL bad_path2 = False;
int count=0; int count=0;
NTSTATUS error = NT_STATUS_OK; NTSTATUS error = NT_STATUS_OK;
BOOL exists=False;
BOOL rc = True; BOOL rc = True;
SMB_STRUCT_STAT sbuf1, sbuf2; SMB_STRUCT_STAT sbuf1, sbuf2;
@@ -3056,7 +3055,8 @@ NTSTATUS rename_internals(connection_struct *conn,
pstrcpy(newname, tmpstr); 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, case_sensitive, case_preserve, short_case_preserve, directory,
newname, newname_last_component, is_short_name)); newname, newname_last_component, is_short_name));
@@ -3094,33 +3094,75 @@ NTSTATUS rename_internals(connection_struct *conn,
} }
} }
if(replace_if_exists) { resolve_wildcards(directory,newname);
/* /*
* NT SMB specific flag - rename can overwrite * The source object must exist.
* file with the same name so don't check for
* vfs_file_exist().
*/ */
if(resolve_wildcards(directory,newname) && if (!vfs_object_exist(conn, directory, NULL)) {
can_rename(directory,conn) && DEBUG(3,("rename_internals: source doesn't exist doing rename %s -> %s\n",
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++;
}
DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
directory,newname)); directory,newname));
if (!count) exists = vfs_file_exist(conn,directory,NULL); if (errno == ENOTDIR || errno == EISDIR || errno == ENOENT) {
if (!count && exists && vfs_file_exist(conn,newname,NULL)) { /*
exists = True; * Must return different errors depending on whether the parent
error = NT_STATUS_OBJECT_NAME_COLLISION; * 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;
}
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 { } else {
/* /*
* Wildcards - process each file that matches. * Wildcards - process each file that matches.
@@ -3148,7 +3190,8 @@ NTSTATUS rename_internals(connection_struct *conn,
error = NT_STATUS_ACCESS_DENIED; error = NT_STATUS_ACCESS_DENIED;
slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname); 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)); DEBUG(6,("rename %s refused\n", fname));
continue; continue;
} }

View File

@@ -231,10 +231,10 @@ int vfs_mkdir(connection_struct *conn, const char *name, mode_t mode)
} }
/******************************************************************* /*******************************************************************
Check if a vfs file exists. Check if an object exists in the vfs.
********************************************************************/ ********************************************************************/
BOOL vfs_file_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf) BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
{ {
SMB_STRUCT_STAT st; SMB_STRUCT_STAT st;
@@ -243,9 +243,26 @@ BOOL vfs_file_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *s
ZERO_STRUCTP(sbuf); ZERO_STRUCTP(sbuf);
if (vfs_stat(conn,fname,sbuf) != 0) if (vfs_stat(conn,fname,sbuf) == -1)
return(False); return(False);
return True;
}
/*******************************************************************
Check if a file exists in the vfs.
********************************************************************/
BOOL vfs_file_exist(connection_struct *conn,char *fname,SMB_STRUCT_STAT *sbuf)
{
SMB_STRUCT_STAT st;
if (!sbuf)
sbuf = &st;
ZERO_STRUCTP(sbuf);
if (vfs_stat(conn,fname,sbuf) == -1)
return False;
return(S_ISREG(sbuf->st_mode)); return(S_ISREG(sbuf->st_mode));
} }