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:
@@ -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.
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user