summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h5
-rw-r--r--source3/include/smb.h15
-rw-r--r--source3/locking/locking.c45
-rw-r--r--source3/locking/locking_shm.c29
-rw-r--r--source3/locking/locking_slow.c59
-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
10 files changed, 225 insertions, 41 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 9b707adeef..9c78e84017 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -538,7 +538,8 @@ int get_share_modes(connection_struct *conn,
share_mode_entry **shares);
void del_share_mode(int token, files_struct *fsp);
BOOL set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type);
-BOOL remove_share_oplock(files_struct *fsp, int token);
+BOOL remove_share_oplock(int token, files_struct *fsp);
+BOOL modify_share_mode(int token, files_struct *fsp, int new_mode);
int share_mode_forall(void (*fn)(share_mode_entry *, char *));
void share_status(FILE *f);
@@ -2147,6 +2148,8 @@ void file_close_conn(connection_struct *conn);
void file_init(void);
void file_close_user(int vuid);
files_struct *file_find_dit(SMB_DEV_T dev, SMB_INO_T inode, struct timeval *tval);
+files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode);
+files_struct *file_find_di_next(files_struct *start_fsp);
files_struct *file_find_print(void);
void file_sync_all(connection_struct *conn);
void fd_ptr_free(file_fd_struct *fd_ptr);
diff --git a/source3/include/smb.h b/source3/include/smb.h
index d71d1cd1eb..2e27fa195f 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -201,14 +201,19 @@ implemented */
#define GET_DENY_MODE(x) (((x)>>SHARE_MODE_SHIFT) & SHARE_MODE_MASK)
#define SET_DENY_MODE(x) ((x)<<SHARE_MODE_SHIFT)
+/* Sync on open file (not sure if used anymore... ?) */
+#define FILE_SYNC_OPENMODE (1<<14)
+#define GET_FILE_SYNC_OPENMODE(x) (((x) & FILE_SYNC_OPENMODE) ? True : False)
+
/* allow delete on open file mode (used by NT SMB's). */
#define ALLOW_SHARE_DELETE (1<<15)
-#define GET_ALLOW_SHARE_DELETE(x) (((x) & ALLOW_SHARE_DELETE) ? 1 : 0)
+#define GET_ALLOW_SHARE_DELETE(x) (((x) & ALLOW_SHARE_DELETE) ? True : False)
#define SET_ALLOW_SHARE_DELETE(x) ((x) ? ALLOW_SHARE_DELETE : 0)
-/* Sync on open file (not sure if used anymore... ?) */
-#define FILE_SYNC_OPENMODE (1<<14)
-#define GET_FILE_SYNC_OPENMODE(x) (((x) & FILE_SYNC_OPENMODE) ? 1 : 0)
+/* delete on close flag (used by NT SMB's). */
+#define DELETE_ON_CLOSE_FLAG (1<<16)
+#define GET_DELETE_ON_CLOSE_FLAG(x) (((x) & DELETE_ON_CLOSE_FLAG) ? True : False)
+#define SET_DELETE_ON_CLOSE_FLAG(x) ((x) ? DELETE_ON_CLOSE_FLAG : 0)
/* open disposition values */
#define FILE_EXISTS_FAIL 0
@@ -669,7 +674,7 @@ struct share_ops {
int (*get_entries)(connection_struct *, int , SMB_DEV_T , SMB_INO_T , share_mode_entry **);
void (*del_entry)(int , files_struct *);
BOOL (*set_entry)(int, files_struct *, uint16 , uint16 );
- BOOL (*remove_oplock)(files_struct *, int);
+ BOOL (*mod_entry)(int, files_struct *, void (*)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *), void *);
int (*forall)(void (*)(share_mode_entry *, char *));
void (*status)(FILE *);
};
diff --git a/source3/locking/locking.c b/source3/locking/locking.c
index f088720e0a..b71b775524 100644
--- a/source3/locking/locking.c
+++ b/source3/locking/locking.c
@@ -230,11 +230,52 @@ BOOL set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type)
}
/*******************************************************************
+ Static function that actually does the work for the generic function
+ below.
+********************************************************************/
+
+static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode,
+ void *param)
+{
+ DEBUG(10,("remove_share_oplock_fn: removing oplock info for entry dev=%x ino=%.0f\n",
+ (unsigned int)dev, (double)inode ));
+ /* Delete the oplock info. */
+ entry->op_port = 0;
+ entry->op_type = 0;
+}
+
+/*******************************************************************
Remove an oplock port and mode entry from a share mode.
********************************************************************/
-BOOL remove_share_oplock(files_struct *fsp, int token)
+
+BOOL remove_share_oplock(int token, files_struct *fsp)
+{
+ return share_ops->mod_entry(token, fsp, remove_share_oplock_fn, NULL);
+}
+
+/*******************************************************************
+ Static function that actually does the work for the generic function
+ below.
+********************************************************************/
+
+static void modify_share_mode_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode,
+ void *param)
+{
+ int new_share_mode = *(int *)param;
+ DEBUG(10,("modify_share_mode_fn: changing share mode info from %x to %x for entry dev=%x ino=%.0f\n",
+ entry->share_mode, new_share_mode, (unsigned int)dev, (double)inode ));
+ /* Change the share mode info. */
+ entry->share_mode = new_share_mode;
+}
+
+/*******************************************************************
+ Modify a share mode on a file. Used by the delete open file code.
+ Return False on fail, True on success.
+********************************************************************/
+
+BOOL modify_share_mode(int token, files_struct *fsp, int new_mode)
{
- return share_ops->remove_oplock(fsp, token);
+ return share_ops->mod_entry(token, fsp, modify_share_mode_fn, (void *)&new_mode);
}
/*******************************************************************
diff --git a/source3/locking/locking_shm.c b/source3/locking/locking_shm.c
index 1077cf23eb..375a8b7f10 100644
--- a/source3/locking/locking_shm.c
+++ b/source3/locking/locking_shm.c
@@ -495,9 +495,12 @@ static BOOL shm_set_share_mode(int token, files_struct *fsp, uint16 port, uint16
}
/*******************************************************************
-Remove an oplock port and mode entry from a share mode.
+ Call a generic modify function for a share mode entry.
********************************************************************/
-static BOOL shm_remove_share_oplock(files_struct *fsp, int token)
+
+static BOOL shm_mod_share_entry(int token, files_struct *fsp,
+ void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *),
+ void *param)
{
SMB_DEV_T dev;
SMB_INO_T inode;
@@ -518,7 +521,7 @@ static BOOL shm_remove_share_oplock(files_struct *fsp, int token)
if(mode_array[hash_entry] == 0)
{
- DEBUG(0,("PANIC ERROR:remove_share_oplock: hash bucket %d empty\n",
+ DEBUG(0,("PANIC ERROR:modify_share_entry: hash bucket %d empty\n",
hash_entry));
return False;
}
@@ -543,14 +546,14 @@ static BOOL shm_remove_share_oplock(files_struct *fsp, int token)
if(!found)
{
- DEBUG(0,("ERROR:remove_share_oplock: no entry found for dev=%x ino=%.0f\n",
+ DEBUG(0,("ERROR:modify_share_entry: no entry found for dev=%x ino=%.0f\n",
(unsigned int)dev, (double)inode));
return False;
}
if(file_scanner_p->locking_version != LOCKING_VERSION)
{
- DEBUG(0,("ERROR: remove_share_oplock: Deleting old share mode v1=%d dev=%x ino=%.0f\n",
+ DEBUG(0,("ERROR: modify_share_entry: Deleting old share mode v1=%d dev=%x ino=%.0f\n",
file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
if(file_prev_p == file_scanner_p)
@@ -571,9 +574,14 @@ static BOOL shm_remove_share_oplock(files_struct *fsp, int token)
(memcmp(&entry_scanner_p->e.time,
&fsp->open_time,sizeof(struct timeval)) == 0) )
{
- /* Delete the oplock info. */
- entry_scanner_p->e.op_port = 0;
- entry_scanner_p->e.op_type = 0;
+ /*
+ * Call the generic function with the given parameter.
+ */
+
+ DEBUG(5,("modify_share_entry: Calling generic function to modify entry for dev=%x ino=%.0f\n",
+ (unsigned int)dev, (double)inode));
+
+ (*mod_fn)( &entry_scanner_p->e, dev, inode, param);
found = True;
break;
}
@@ -586,7 +594,7 @@ static BOOL shm_remove_share_oplock(files_struct *fsp, int token)
if(!found)
{
- DEBUG(0,("ERROR: remove_share_oplock: No oplock granted. dev=%x ino=%.0f\n",
+ DEBUG(0,("ERROR: modify_share_entry: No entry found for dev=%x ino=%.0f\n",
(unsigned int)dev, (double)inode));
return False;
}
@@ -594,7 +602,6 @@ static BOOL shm_remove_share_oplock(files_struct *fsp, int token)
return True;
}
-
/*******************************************************************
call the specified function on each entry under management by the
share mode system
@@ -670,7 +677,7 @@ static struct share_ops share_ops = {
shm_get_share_modes,
shm_del_share_mode,
shm_set_share_mode,
- shm_remove_share_oplock,
+ shm_mod_share_entry,
shm_share_forall,
shm_share_status,
};
diff --git a/source3/locking/locking_slow.c b/source3/locking/locking_slow.c
index f2c2d3e9d9..f1e0fa2149 100644
--- a/source3/locking/locking_slow.c
+++ b/source3/locking/locking_slow.c
@@ -827,9 +827,12 @@ mode 0x%X pid=%d\n",fname,fsp->share_mode,pid));
}
/*******************************************************************
-Remove an oplock port and mode entry from a share mode.
+ Call a generic modify function for a share mode entry.
********************************************************************/
-static BOOL slow_remove_share_oplock(files_struct *fsp, int token)
+
+static BOOL slow_mod_share_entry(int token, files_struct *fsp,
+ void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *),
+ void *param)
{
pstring fname;
int fd = (int)token;
@@ -841,20 +844,21 @@ static BOOL slow_remove_share_oplock(files_struct *fsp, int token)
int pid;
BOOL found = False;
BOOL new_file;
+ share_mode_entry entry;
share_name(fsp->conn, fsp->fd_ptr->dev,
fsp->fd_ptr->inode, fname);
if(read_share_file( fsp->conn, fd, fname, &buf, &new_file) != 0)
{
- DEBUG(0,("ERROR: remove_share_oplock: Failed to read share file %s\n",
+ DEBUG(0,("ERROR: slow_mod_share_entry: Failed to read share file %s\n",
fname));
return False;
}
if(new_file == True)
{
- DEBUG(0,("ERROR: remove_share_oplock: share file %s is new (size zero), \
+ DEBUG(0,("ERROR: slow_mod_share_entry: share file %s is new (size zero), \
deleting it.\n", fname));
delete_share_file(fsp->conn, fname);
return False;
@@ -862,13 +866,13 @@ deleting it.\n", fname));
num_entries = IVAL(buf,SMF_NUM_ENTRIES_OFFSET);
- DEBUG(5,("remove_share_oplock: share file %s has %d share mode entries.\n",
+ DEBUG(5,("slow_mod_share_entry: share file %s has %d share mode entries.\n",
fname, num_entries));
/* PARANOIA TEST */
if(num_entries < 0)
{
- DEBUG(0,("PANIC ERROR:remove_share_oplock: num_share_mode_entries < 0 (%d) \
+ DEBUG(0,("PANIC ERROR:slow_mod_share_entry: num_share_mode_entries < 0 (%d) \
for share file %s\n", num_entries, fname));
return False;
}
@@ -876,7 +880,7 @@ for share file %s\n", num_entries, fname));
if(num_entries == 0)
{
/* No entries - just delete the file. */
- DEBUG(0,("remove_share_oplock: share file %s has no share mode entries - deleting.\n",
+ DEBUG(0,("slow_mod_share_entry: share file %s has no share mode entries - deleting.\n",
fname));
if(buf)
free(buf);
@@ -886,10 +890,6 @@ for share file %s\n", num_entries, fname));
pid = getpid();
- /* Go through the entries looking for the particular one
- we have set - remove the oplock settings on it.
- */
-
base = buf + SMF_HEADER_LENGTH + SVAL(buf,SMF_FILENAME_LEN_OFFSET);
for(i = 0; i < num_entries; i++)
@@ -902,18 +902,41 @@ for share file %s\n", num_entries, fname));
(IVAL(p,SME_PID_OFFSET) != pid))
continue;
- DEBUG(5,("remove_share_oplock: clearing oplock on entry number %d (of %d) \
+ DEBUG(5,("slow_mod_share_entry: Calling generic function to modify entry number %d (of %d) \
from the share file %s\n", i, num_entries, fname));
- SSVAL(p,SME_PORT_OFFSET,0);
- SSVAL(p,SME_OPLOCK_TYPE_OFFSET,0);
+ /*
+ * Copy into the share_mode_entry structure and then call
+ * the generic function with the given parameter.
+ */
+
+ entry.pid = IVAL(p,SME_PID_OFFSET);
+ entry.op_port = SVAL(p,SME_PORT_OFFSET);
+ entry.op_type = SVAL(p,SME_OPLOCK_TYPE_OFFSET);
+ entry.share_mode = IVAL(p,SME_SHAREMODE_OFFSET);
+ entry.time.tv_sec = IVAL(p,SME_SEC_OFFSET)
+ entry.time.tv_sec = IVAL(p,SME_USEC_OFFSET);
+
+ (*mod_fn)( &entry, fsp->fd_ptr->dev, fsp->fd_ptr->inode, param);
+
+ /*
+ * Now copy any changes the function made back into the buffer.
+ */
+
+ SIVAL(p,SME_PID_OFFSET, entry.pid)
+ SSVAL(p,SME_PORT_OFFSET,entry.op_port);
+ SSVAL(p,SME_OPLOCK_TYPE_OFFSET,entry.op_type);
+ SIVAL(p,SME_SHAREMODE_OFFSET,entry.share_mode);
+ SIVAL(p,SME_SEC_OFFSET,entry.time.tv_sec)
+ SIVAL(p,SME_USEC_OFFSET,entry.time.tv_sec);
+
found = True;
break;
}
if(!found)
{
- DEBUG(0,("remove_share_oplock: entry not found in share file %s\n", fname));
+ DEBUG(0,("slow_mod_share_entry: entry not found in share file %s\n", fname));
if(buf)
free(buf);
return False;
@@ -922,7 +945,7 @@ from the share file %s\n", i, num_entries, fname));
/* Re-write the file - and truncate it at the correct point. */
if(sys_lseek(fd, (SMB_OFF_T)0, SEEK_SET) != 0)
{
- DEBUG(0,("ERROR: remove_share_oplock: lseek failed to reset to \
+ DEBUG(0,("ERROR: slow_mod_share_entry: lseek failed to reset to \
position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
if(buf)
free(buf);
@@ -932,7 +955,7 @@ position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
fsize = (base - buf) + (SMF_ENTRY_LENGTH*num_entries);
if(write(fd, buf, fsize) != fsize)
{
- DEBUG(0,("ERROR: remove_share_oplock: failed to re-write share \
+ DEBUG(0,("ERROR: slow_mod_share_entry: failed to re-write share \
mode file %s (%s)\n", fname, strerror(errno)));
if(buf)
free(buf);
@@ -1048,7 +1071,7 @@ static struct share_ops share_ops = {
slow_get_share_modes,
slow_del_share_mode,
slow_set_share_mode,
- slow_remove_share_oplock,
+ slow_mod_share_entry,
slow_share_forall,
slow_share_status,
};
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;