diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/close.c | 1 | ||||
-rw-r--r-- | source3/smbd/files.c | 35 | ||||
-rw-r--r-- | source3/smbd/open.c | 23 | ||||
-rw-r--r-- | source3/smbd/reply.c | 2 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 52 |
5 files changed, 109 insertions, 4 deletions
diff --git a/source3/smbd/close.c b/source3/smbd/close.c index 2dba691a1c..50ad01f575 100644 --- a/source3/smbd/close.c +++ b/source3/smbd/close.c @@ -142,6 +142,7 @@ void close_file(files_struct *fsp, BOOL normal_close) */ if (normal_close && last_reference && delete_on_close) { + DEBUG(5,("close_file: file %s. Delete on close was set - deleting file.\n")); if(dos_unlink(fsp->fsp_name) != 0) DEBUG(0,("close_file: file %s. Delete on close was set and unlink failed \ with error %s\n", fsp->fsp_name, strerror(errno) )); diff --git a/source3/smbd/files.c b/source3/smbd/files.c index c369a45bab..e58c3834a0 100644 --- a/source3/smbd/files.c +++ b/source3/smbd/files.c @@ -277,6 +277,41 @@ files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval return NULL; } +/**************************************************************************** + Find the first fsp given a device and inode. +****************************************************************************/ + +files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode) +{ + files_struct *fsp; + + for (fsp=Files;fsp;fsp=fsp->next) { + if (fsp->open && + fsp->fd_ptr->dev == dev && + fsp->fd_ptr->inode == inode ) + return fsp; + } + + return NULL; +} + +/**************************************************************************** + Find the next fsp having the same device and inode. +****************************************************************************/ + +files_struct *file_find_di_next(files_struct *start_fsp) +{ + files_struct *fsp; + + for (fsp = start_fsp->next;fsp;fsp=fsp->next) { + if (fsp->open && + fsp->fd_ptr->dev == start_fsp->fd_ptr->dev && + fsp->fd_ptr->inode == start_fsp->fd_ptr->inode ) + return fsp; + } + + return NULL; +} /**************************************************************************** find a fsp that is open for printing diff --git a/source3/smbd/open.c b/source3/smbd/open.c index b6b2ef5bb8..aac4b02fba 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -659,6 +659,26 @@ static int check_share_mode( share_mode_entry *share, int deny_mode, int old_open_mode = GET_OPEN_MODE(share->share_mode); int old_deny_mode = GET_DENY_MODE(share->share_mode); + /* + * Setup the potential error to return. + */ + + unix_ERR_class = ERRDOS; + unix_ERR_code = ERRbadshare; + + /* + * Don't allow any open once the delete on close flag has been + * set. + */ + + if(GET_DELETE_ON_CLOSE_FLAG(share->share_mode)) + { + DEBUG(5,("check_share_mode: Failing open on file %s as delete on close flag is set.\n", + fname )); + unix_ERR_code = ERRnoaccess; + return False; + } + if (old_deny_mode > 4 || old_open_mode > 2) { DEBUG(0,("Invalid share mode found (%d,%d,%d) on file %s\n", @@ -688,6 +708,7 @@ static int check_share_mode( share_mode_entry *share, int deny_mode, *flags = O_WRONLY; } + return True; } @@ -865,8 +886,6 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou free((char *)old_shares); unlock_share_entry(conn, dev, inode, token); errno = EACCES; - unix_ERR_class = ERRDOS; - unix_ERR_code = ERRbadshare; return; } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index bc19f1a931..babdd2056c 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3615,7 +3615,7 @@ no oplock granted on this file.\n", fsp->fnum)); /* Remove the oplock flag from the sharemode. */ lock_share_entry(fsp->conn, dev, inode, &token); - if(remove_share_oplock(fsp, token)==False) { + if(remove_share_oplock(token, fsp)==False) { DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \ dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode)); diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index f8d90cd871..1c2bdb1ddf 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1655,14 +1655,64 @@ static int call_trans2setfilepathinfo(connection_struct *conn, { if (tran_call == TRANSACT2_SETFILEINFO) { files_struct *fsp = file_fsp(params,0); + BOOL delete_on_close = (CVAL(pdata,0) ? True : False); + if(fsp->is_directory) return(ERROR(ERRDOS,ERRnoaccess)); + + /* + * We can only set the delete on close flag if + * the share mode contained ALLOW_SHARE_DELETE + */ + + if(!GET_ALLOW_SHARE_DELETE(fsp->share_mode)) + return(ERROR(ERRDOS,ERRnoaccess)); + + /* + * If the flag has changed from its previous value then + * modify the share mode entry for all files we have open + * on this device and inode to tell other smbds we have + * changed the delete on close flag. + */ + + if(GET_DELETE_ON_CLOSE_FLAG(fsp->share_mode) != delete_on_close) + { + int token; + files_struct *iterate_fsp; + SMB_DEV_T dev = fsp->fd_ptr->dev; + SMB_INO_T inode = fsp->fd_ptr->inode; + int new_share_mode = (delete_on_close ? + (fsp->share_mode | DELETE_ON_CLOSE_FLAG) : + (fsp->share_mode & ~DELETE_ON_CLOSE_FLAG) ); + + DEBUG(10,("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n", + delete_on_close ? "Adding" : "Removing", fsp->fnum, fsp->fsp_name )); + + if(lock_share_entry(fsp->conn, dev, inode, &token) == False) + return(ERROR(ERRDOS,ERRnoaccess)); + + /* + * Go through all files we have open on the same device and + * inode (hanging off the same hash bucket) and set the DELETE_ON_CLOSE_FLAG. + */ + + for(iterate_fsp = file_find_di_first(dev, inode); iterate_fsp; + iterate_fsp = file_find_di_next(iterate_fsp)) + { + if(modify_share_mode(token, iterate_fsp, new_share_mode)==False) + DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close for fnum %d, \ +dev = %x, inode = %.0f\n", fsp->fnum, (unsigned int)dev, (double)inode)); + } + + unlock_share_entry(fsp->conn, dev, inode, token); + } + /* * Set the delete on close flag in the reference * counted struct. Delete when the last reference * goes away. */ - fsp->fd_ptr->delete_on_close = CVAL(pdata,0); + fsp->fd_ptr->delete_on_close = delete_on_close; } else return(ERROR(ERRDOS,ERRunknownlevel)); break; |