summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>1998-10-23 03:34:50 +0000
committerJeremy Allison <jra@samba.org>1998-10-23 03:34:50 +0000
commit9bb7ac81b6e4d33e1be49447dbdbbb8d24259f53 (patch)
tree0bffe55dcb3dee8574d89546af83bd44cd476491 /source3/smbd
parent1e60cc49f5ecb864ab965a6e7ab9287e1204d1d6 (diff)
downloadsamba-9bb7ac81b6e4d33e1be49447dbdbbb8d24259f53.tar.gz
samba-9bb7ac81b6e4d33e1be49447dbdbbb8d24259f53.tar.bz2
samba-9bb7ac81b6e4d33e1be49447dbdbbb8d24259f53.zip
Reasonably large change to give us *exactly* correct NT delete on close semantics.
This was trickier than it looks :-). Check out the new DELETE_ON_CLOSE flag in the share modes and the new code that iterates through all open files on the same device and inode in files.c and trans2.c Also changed the code that modifies share mode entries to take generic function pointers rather than doing a specific thing so this sort of change should be easier in the future. Jeremy. (This used to be commit 5e6a7cd99d29d1cf068fc517272559c1cf47ea3a)
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/close.c1
-rw-r--r--source3/smbd/files.c35
-rw-r--r--source3/smbd/open.c23
-rw-r--r--source3/smbd/reply.c2
-rw-r--r--source3/smbd/trans2.c52
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;