Index: SAMBA_3_0/source/smbd/close.c =================================================================== --- SAMBA_3_0/source/smbd/close.c (revision 12097) +++ SAMBA_3_0/source/smbd/close.c (working copy) @@ -227,18 +227,32 @@ static int close_normal_file(files_struc */ if (normal_close && delete_file) { + SMB_STRUCT_STAT sbuf; + /* + * Use lck->filename instead of fsp->fsp_name here because + * filename may be renamed by another smbd process. + * See https://bugzilla.samba.org/show_bug.cgi?id=3303 + */ DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n", - fsp->fsp_name)); - if(SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) { - /* - * This call can potentially fail as another smbd may have - * had the file open with delete on close set and deleted - * it when its last reference to this file went away. Hence - * we log this but not at debug level zero. - */ - - DEBUG(5,("close_file: file %s. Delete on close was set and unlink failed \ -with error %s\n", fsp->fsp_name, strerror(errno) )); + lck->filename)); + if(SMB_VFS_STAT(conn,lck->filename,&sbuf) != 0) { + DEBUG(5,("close_file: file %s. Delete on close was set and stat failed \ +with error %s\n", lck->filename, strerror(errno) )); + } else { + if(sbuf.st_dev != fsp->dev || sbuf.st_ino != fsp->inode) { + DEBUG(5,("close_file: file %s. Delete on close was set and dev and/or inode not mismatch\n", + lck->filename )); + } else if(SMB_VFS_UNLINK(conn,lck->filename) != 0) { + /* + * This call can potentially fail as another smbd may have + * had the file open with delete on close set and deleted + * it when its last reference to this file went away. Hence + * we log this but not at debug level zero. + */ + + DEBUG(5,("close_file: file %s. Delete on close was set and unlink failed \ +with error %s\n", lck->filename, strerror(errno) )); + } } process_pending_change_notify_queue((time_t)0); } Index: SAMBA_3_0/source/smbd/reply.c =================================================================== --- SAMBA_3_0/source/smbd/reply.c (revision 12097) +++ SAMBA_3_0/source/smbd/reply.c (working copy) @@ -4144,6 +4144,7 @@ NTSTATUS rename_internals_fsp(connection NTSTATUS error = NT_STATUS_OK; BOOL dest_exists; BOOL rcdest = True; + struct share_mode_lock *lck; ZERO_STRUCT(sbuf); rcdest = unix_convert(newname,conn,newname_last_component,&bad_path,&sbuf); @@ -4231,13 +4232,24 @@ NTSTATUS rename_internals_fsp(connection return NT_STATUS_ACCESS_DENIED; } + lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, fsp->fsp_name); + if (lck == NULL) { + DEBUG(0,("rename_internals_fsp: Could not get share mode lock for file %s\n", + fsp->fsp_name)); + return NT_STATUS_ACCESS_DENIED; + } + 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); + set_share_filename(lck, newname); + talloc_free(lck); return NT_STATUS_OK; } + talloc_free(lck); + if (errno == ENOTDIR || errno == EISDIR) error = NT_STATUS_OBJECT_NAME_COLLISION; else @@ -4268,6 +4280,7 @@ NTSTATUS rename_internals(connection_str BOOL rc = True; BOOL rcdest = True; SMB_STRUCT_STAT sbuf1, sbuf2; + struct share_mode_lock *lck; *directory = *mask = 0; @@ -4453,13 +4466,24 @@ directory = %s, newname = %s, last_compo return NT_STATUS_SHARING_VIOLATION; } + lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino, directory); + if (lck == NULL) { + DEBUG(0,("rename_internals: Could not get share mode lock for file %s\n", + directory)); + return NT_STATUS_ACCESS_DENIED; + } + 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); + set_share_filename(lck, newname); + talloc_free(lck); return NT_STATUS_OK; } + talloc_free(lck); + if (errno == ENOTDIR || errno == EISDIR) error = NT_STATUS_OBJECT_NAME_COLLISION; else @@ -4555,11 +4579,22 @@ directory = %s, newname = %s, last_compo return NT_STATUS_SHARING_VIOLATION; } + lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino, fname); + if (lck == NULL) { + DEBUG(0,("rename_internals: Could not get share mode lock for file %s\n", + fname)); + error = NT_STATUS_ACCESS_DENIED; + continue; + } + if (!SMB_VFS_RENAME(conn,fname,destname)) { rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname); + set_share_filename(lck, newname); count++; error = NT_STATUS_OK; } + talloc_free(lck); + DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname)); } CloseDir(dir_hnd); Index: SAMBA_3_0/source/locking/locking.c =================================================================== --- SAMBA_3_0/source/locking/locking.c (revision 12097) +++ SAMBA_3_0/source/locking/locking.c (working copy) @@ -891,6 +891,26 @@ BOOL remove_all_share_oplocks(struct sha return True; } +/******************************************************************* + Sets the filename for rename. +********************************************************************/ +BOOL set_share_filename(struct share_mode_lock *lck, const char *fname) +{ + char *temp; + + temp = (char *)TALLOC_REALLOC(lck, (void *)lck->filename, strlen(fname) + 1); + if (temp == NULL) { + DEBUG(0, ("talloc_realloc failed\n")); + return False; + } + pstrcpy(temp, fname); + + lck->filename = temp; + lck->modified = True; + + return True; +} + /**************************************************************************** Deal with the internal needs of setting the delete on close flag. Note that as the tdb locking is recursive, it is safe to call this from within