diff options
author | Volker Lendecke <vlendec@samba.org> | 2007-06-13 09:55:13 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:23:17 -0500 |
commit | 0342ce7057045a362134281bcc7030111276dea0 (patch) | |
tree | c72f373f04cab297ad2a93e57d89b98fcf820cb8 /source/smbd | |
parent | c23e08cc09b8de860ab9c7ac9d0e7c2502dfccd9 (diff) | |
download | samba-0342ce7057045a362134281bcc7030111276dea0.tar.gz samba-0342ce7057045a362134281bcc7030111276dea0.tar.xz samba-0342ce7057045a362134281bcc7030111276dea0.zip |
r23457: After Jeremy's ack:
The attached patch removes a little race condition for
people with real kernel oplock support, and reduces some
code paths. It changes reply_unlink to open_file_ntcreate,
set_delete_on_close and close_file.
The race condition happens if we break the oplock in
can_delete via open_file_ntcreate, we close the file,
someone else gets a batch oplock and we try to unlink.
It reduces code paths by calling SMB_VFS_UNLINK in 2 fewer
places.
Diffstat (limited to 'source/smbd')
-rw-r--r-- | source/smbd/reply.c | 53 |
1 files changed, 29 insertions, 24 deletions
diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 6490856f04f..be350994701 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1830,11 +1830,11 @@ static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, } /******************************************************************* - Check if a user is allowed to delete a file. -********************************************************************/ + * unlink a file with all relevant access checks + *******************************************************************/ -static NTSTATUS can_delete(connection_struct *conn, char *fname, - uint32 dirtype, BOOL can_defer) +static NTSTATUS do_unlink(connection_struct *conn, char *fname, + uint32 dirtype, BOOL can_defer) { SMB_STRUCT_STAT sbuf; uint32 fattr; @@ -1935,10 +1935,19 @@ static NTSTATUS can_delete(connection_struct *conn, char *fname, can_defer ? 0 : INTERNAL_OPEN_ONLY, NULL, &fsp); - if (NT_STATUS_IS_OK(status)) { - close_file(fsp,NORMAL_CLOSE); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("open_file_ntcreate failed: %s\n", + nt_errstr(status))); + return status; } - return status; + + /* The set is across all open files on this dev/inode pair. */ + if (!set_delete_on_close(fsp, True, ¤t_user.ut)) { + close_file(fsp, NORMAL_CLOSE); + return NT_STATUS_ACCESS_DENIED; + } + + return close_file(fsp,NORMAL_CLOSE); } /**************************************************************************** @@ -1997,17 +2006,15 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, return status; } - status = can_delete(conn,directory,dirtype,can_defer); + status = do_unlink(conn,directory,dirtype,can_defer); if (!NT_STATUS_IS_OK(status)) { return status; } - if (SMB_VFS_UNLINK(conn,directory) == 0) { - count++; - notify_fname(conn, NOTIFY_ACTION_REMOVED, - FILE_NOTIFY_CHANGE_FILE_NAME, - directory); - } + count++; + notify_fname(conn, NOTIFY_ACTION_REMOVED, + FILE_NOTIFY_CHANGE_FILE_NAME, + directory); } else { struct smb_Dir *dir_hnd = NULL; long offset = 0; @@ -2066,19 +2073,17 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, return status; } - status = can_delete(conn, fname, dirtype, can_defer); + status = do_unlink(conn, fname, dirtype, can_defer); if (!NT_STATUS_IS_OK(status)) { continue; } - if (SMB_VFS_UNLINK(conn,fname) == 0) { - count++; - DEBUG(3,("unlink_internals: succesful unlink " - "[%s]\n",fname)); - notify_fname(conn, NOTIFY_ACTION_REMOVED, - FILE_NOTIFY_CHANGE_FILE_NAME, - fname); - } - + + count++; + DEBUG(3,("unlink_internals: succesful unlink [%s]\n", + fname)); + notify_fname(conn, NOTIFY_ACTION_REMOVED, + FILE_NOTIFY_CHANGE_FILE_NAME, + fname); } CloseDir(dir_hnd); } |