summaryrefslogtreecommitdiff
path: root/source3/smbd/trans2.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2001-03-30 08:57:24 +0000
committerJeremy Allison <jra@samba.org>2001-03-30 08:57:24 +0000
commit6e7f03f9b920d1b81056959cca8c0b27ada4ee2d (patch)
treebf6426290c5aae2012dc4769158b3495cbbc031f /source3/smbd/trans2.c
parent9874ebc3d3355465f884f3aad4d69914a4e1f0c5 (diff)
downloadsamba-6e7f03f9b920d1b81056959cca8c0b27ada4ee2d.tar.gz
samba-6e7f03f9b920d1b81056959cca8c0b27ada4ee2d.tar.bz2
samba-6e7f03f9b920d1b81056959cca8c0b27ada4ee2d.zip
This is a big, rather ugly patch. Whilst investigating the files not truncated
when copying to a full disk problem, I discovered that we were not allowing the delete on close flag to be set properly, this led to other things, and after investigation of the proper delete on close semantics and their relationship to the file_share_delete flag I discovered there were some cases where we weren't doing the deny modes properly. And this after only 5 years working on them..... :-) :-). So here's the latest attempt. I realised the delete on close flag needs to be set across all smbds with a dev/ino pair open - in addition, the delete on close flag, allow share delete and delete access requested all need to be stored in the share mode tdb. The "delete_on_close" entry in the fsp struct is now redundant and should really be removed. This may also mean we can get rid of the "iterate_fsp" calls that I didn't like adding in the first place. Whilst doing this patch, I also discovered we needed to do the se_map_generic() call for file opens and POSIX ACL mapping, so I added that also. This code, although ugly, now passes the deny mode torture tests plus the delete on close tests I added. I do need to add one more multiple connection delete on close test to make sure I got the semantics exactly right, plus we should also (as Andrew suggested) move to random testing here. The good news is that NT should now correctly delete the file on disk full error when copying to a disk :-). Jeremy. (This used to be commit 51987684bd231c744da2e5f3705fd236d5616173)
Diffstat (limited to 'source3/smbd/trans2.c')
-rw-r--r--source3/smbd/trans2.c218
1 files changed, 84 insertions, 134 deletions
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 5a7a5c72cb..be130247c0 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -1800,144 +1800,94 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
{
- if ((tran_call == TRANSACT2_SETFILEINFO) && (fsp != NULL))
- {
- BOOL delete_on_close = (CVAL(pdata,0) ? True : False);
+ BOOL delete_on_close = (CVAL(pdata,0) ? True : False);
- if(fsp->is_directory)
- {
- fsp->directory_delete_on_close = delete_on_close;
- DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, directory %s\n",
- delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+ if (tran_call != TRANSACT2_SETFILEINFO)
+ return(ERROR(ERRDOS,ERRunknownlevel));
- }
- else if(fsp->stat_open)
- {
- DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, stat open %s\n",
- delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
- }
- else
- {
+ if (fsp == NULL)
+ return(UNIXERROR(ERRDOS,ERRbadfid));
- /*
- * 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 been set 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(delete_on_close && !GET_DELETE_ON_CLOSE_FLAG(fsp->share_mode))
- {
- int i;
- files_struct *iterate_fsp;
- SMB_DEV_T dev = fsp->dev;
- SMB_INO_T inode = fsp->inode;
- int num_share_modes;
- share_mode_entry *current_shares = NULL;
-
- if (lock_share_entry_fsp(fsp) == False)
- return(ERROR(ERRDOS,ERRnoaccess));
-
- /*
- * Before we allow this we need to ensure that all current opens
- * on the file have the GET_ALLOW_SHARE_DELETE flag set. If they
- * do not then we deny this (as we are essentially deleting the
- * file at this point.
- */
-
- num_share_modes = get_share_modes(conn, dev, inode, &current_shares);
- for(i = 0; i < num_share_modes; i++)
- {
- if(!GET_ALLOW_SHARE_DELETE(current_shares[i].share_mode))
- {
- DEBUG(5,("call_trans2setfilepathinfo: refusing to set delete on close flag for fnum = %d, \
-file %s as a share exists that was not opened with FILE_DELETE access.\n",
- fsp->fnum, fsp->fsp_name ));
- /*
- * Release the lock.
- */
-
- unlock_share_entry_fsp(fsp);
-
- /*
- * current_shares was malloced by get_share_modes - free it here.
- */
-
- free((char *)current_shares);
-
- /*
- * Even though share violation would be more appropriate here,
- * return ERRnoaccess as that's what NT does.
- */
-
- return(ERROR(ERRDOS,ERRnoaccess));
- }
- }
-
- /*
- * current_shares was malloced by get_share_modes - free it here.
- */
-
- free((char *)current_shares);
-
- 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 ));
-
- /*
- * 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.
- * Other smbd's that have this file open will have to fend for themselves. We
- * take care of this (rare) case in close_file(). See the comment there.
- */
-
- for(iterate_fsp = file_find_di_first(dev, inode); iterate_fsp;
- iterate_fsp = file_find_di_next(iterate_fsp))
- {
- int new_share_mode = (delete_on_close ?
- (iterate_fsp->share_mode | DELETE_ON_CLOSE_FLAG) :
- (iterate_fsp->share_mode & ~DELETE_ON_CLOSE_FLAG) );
-
- DEBUG(10,("call_trans2setfilepathinfo: Changing share mode for fnum %d, file %s \
-dev = %x, inode = %.0f from %x to %x\n",
- iterate_fsp->fnum, iterate_fsp->fsp_name, (unsigned int)dev,
- (double)inode, iterate_fsp->share_mode, new_share_mode ));
-
- if(modify_share_mode(iterate_fsp, new_share_mode, iterate_fsp->oplock_type)==False)
- DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close for fnum %d, \
-dev = %x, inode = %.0f\n", iterate_fsp->fnum, (unsigned int)dev, (double)inode));
- }
-
- /*
- * Set the delete on close flag in the reference
- * counted struct. Delete when the last reference
- * goes away.
- */
- fsp->delete_on_close = delete_on_close;
-
- unlock_share_entry_fsp(fsp);
-
- DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n",
- delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
-
- } /* end if(delete_on_close && !GET_DELETE_ON_CLOSE_FLAG(fsp->share_mode)) */
- } /* end if is_directory. */
- } else
- return(ERROR(ERRDOS,ERRunknownlevel));
- break;
- }
+ /*
+ * Only allow delete on close for files/directories opened with delete intent.
+ */
- default:
- {
- return(ERROR(ERRDOS,ERRunknownlevel));
- }
+ if (delete_on_close && !GET_DELETE_ACCESS_REQUESTED(fsp->share_mode)) {
+ DEBUG(10,("call_trans2setfilepathinfo: file %s delete on close flag set but delete access denied.\n",
+ fsp->fsp_name ));
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+
+ if(fsp->is_directory) {
+ fsp->directory_delete_on_close = delete_on_close;
+ DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, directory %s\n",
+ delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+ } else if(fsp->stat_open) {
+
+ DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, stat open %s\n",
+ delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+
+ } else {
+
+ files_struct *iterate_fsp;
+
+ /*
+ * Modify the share mode entry for all files open
+ * on this device and inode to tell other smbds we have
+ * changed the delete on close flag. This will be noticed
+ * in the close code, the last closer will delete the file
+ * if flag is set.
+ */
+
+ 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(fsp) == False)
+ return(ERROR(ERRDOS,ERRnoaccess));
+
+ if (!modify_delete_flag(fsp->dev, fsp->inode, delete_on_close)) {
+ DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close flag for file %s\n",
+ fsp->fsp_name ));
+ unlock_share_entry_fsp(fsp);
+ return(ERROR(ERRDOS,ERRnoaccess));
+ }
+
+ /*
+ * Release the lock.
+ */
+
+ unlock_share_entry_fsp(fsp);
+
+ /*
+ * 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.
+ * Other smbd's that have this file open will look in the share_mode on close.
+ * take care of this (rare) case in close_file(). See the comment there.
+ * NB. JRA. We don't really need to do this anymore - all should be taken
+ * care of in the share_mode changes in the tdb.
+ */
+
+ for(iterate_fsp = file_find_di_first(fsp->dev, fsp->inode);
+ iterate_fsp; iterate_fsp = file_find_di_next(iterate_fsp))
+ fsp->delete_on_close = delete_on_close;
+
+ /*
+ * Set the delete on close flag in the fsp.
+ */
+ fsp->delete_on_close = delete_on_close;
+
+ DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n",
+ delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+
+ }
+
+ break;
+ }
+
+ default:
+ {
+ return(ERROR(ERRDOS,ERRunknownlevel));
+ }
}
/* get some defaults (no modifications) if any info is zero or -1. */