summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h4
-rw-r--r--source3/include/smb.h20
-rw-r--r--source3/libsmb/clifile.c8
-rw-r--r--source3/locking/locking.c71
-rw-r--r--source3/smbd/close.c45
-rw-r--r--source3/smbd/nttrans.c31
-rw-r--r--source3/smbd/open.c45
-rw-r--r--source3/smbd/posix_acls.c10
-rw-r--r--source3/smbd/trans2.c218
9 files changed, 258 insertions, 194 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 9b6aab6645c..12a7478e0ab 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1155,11 +1155,11 @@ void unlock_share_entry_fsp(files_struct *fsp);
int get_share_modes(connection_struct *conn,
SMB_DEV_T dev, SMB_INO_T inode,
share_mode_entry **shares);
-void del_share_mode(files_struct *fsp);
+size_t del_share_mode(files_struct *fsp, share_mode_entry **ppse);
BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type);
BOOL remove_share_oplock(files_struct *fsp);
BOOL downgrade_share_oplock(files_struct *fsp);
-BOOL modify_share_mode(files_struct *fsp, int new_mode, uint16 new_oplock);
+BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close);
int share_mode_forall(SHAREMODE_FN(fn));
/*The following definitions come from locking/posix.c */
diff --git a/source3/include/smb.h b/source3/include/smb.h
index ba0a02e9507..e154c1eda2a 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -123,6 +123,11 @@ implemented */
#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)
+/* was delete access requested in NT open ? */
+#define DELETE_ACCESS_REQUESTED (1<<17)
+#define GET_DELETE_ACCESS_REQUESTED(x) (((x) & DELETE_ACCESS_REQUESTED) ? True : False)
+#define SET_DELETE_ACCESS_REQUESTED(x) ((x) ? DELETE_ACCESS_REQUESTED : 0)
+
/* open disposition values */
#define FILE_EXISTS_FAIL 0
#define FILE_EXISTS_OPEN 1
@@ -1060,7 +1065,7 @@ struct bitmap {
#define FILE_READ_ATTRIBUTES 0x080
#define FILE_WRITE_ATTRIBUTES 0x100
-#define FILE_ALL_ATTRIBUTES 0x1FF
+#define FILE_ALL_ACCESS 0x1FF
/* the desired access to use when opening a pipe */
#define DESIRED_ACCESS_PIPE 0x2019f
@@ -1088,6 +1093,19 @@ struct bitmap {
#define GENERIC_WRITE_ACCESS (1<<30)
#define GENERIC_READ_ACCESS (((unsigned)1)<<31)
+/* Mapping of generic access rights for files to specific rights. */
+
+#define FILE_GENERIC_ALL (STANDARD_RIGHTS_REQUIRED_ACCESS| SYNCHRONIZE_ACCESS|FILE_ALL_ACCESS)
+
+#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ_ACCESS|FILE_READ_DATA|FILE_READ_ATTRIBUTES|\
+ FILE_READ_EA|SYNCHRONIZE_ACCESS)
+
+#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE_ACCESS|FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES|\
+ FILE_WRITE_EA|FILE_APPEND_DATA|SYNCHRONIZE_ACCESS)
+
+#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE_ACCESS|FILE_READ_ATTRIBUTES|\
+ FILE_EXECUTE|SYNCHRONIZE_ACCESS)
+
/* Mapping of access rights to UNIX perms. */
#define UNIX_ACCESS_RWX (UNIX_ACCESS_R|UNIX_ACCESS_W|UNIX_ACCESS_X)
#define UNIX_ACCESS_R (READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS|\
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index e90bd7c41fa..d62a0a417a6 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -164,6 +164,9 @@ BOOL cli_rmdir(struct cli_state *cli, char *dname)
}
return True;
+}
+
+/****************************************************************************
Set or clear the delete on close flag.
****************************************************************************/
@@ -183,7 +186,7 @@ int cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
data = flag ? 1 : 0;
if (!cli_send_trans(cli, SMBtrans2,
- NULL, 0, /* name, length */
+ NULL, /* name */
-1, 0, /* fid, flags */
&setup, 1, 0, /* setup, length, max */
param, param_len, 2, /* param, length, max */
@@ -205,9 +208,6 @@ int cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
}
/****************************************************************************
-}
-
-/****************************************************************************
open a file - exposing the full horror of the NT API :-).
Used in smbtorture.
****************************************************************************/
diff --git a/source3/locking/locking.c b/source3/locking/locking.c
index 118d59cc10c..5824287e913 100644
--- a/source3/locking/locking.c
+++ b/source3/locking/locking.c
@@ -331,19 +331,24 @@ int get_share_modes(connection_struct *conn,
}
/*******************************************************************
- Del the share mode of a file for this process
+ Del the share mode of a file for this process. Return the number
+ of entries left, and a memdup'ed copy of the entry deleted.
********************************************************************/
-void del_share_mode(files_struct *fsp)
+
+size_t del_share_mode(files_struct *fsp, share_mode_entry **ppse)
{
TDB_DATA dbuf;
struct locking_data *data;
int i, del_count=0;
share_mode_entry *shares;
pid_t pid = sys_getpid();
+ size_t count;
+
+ *ppse = NULL;
/* read in the existing share modes */
dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
- if (!dbuf.dptr) return;
+ if (!dbuf.dptr) return 0;
data = (struct locking_data *)dbuf.dptr;
shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
@@ -354,6 +359,7 @@ void del_share_mode(files_struct *fsp)
if (shares[i].pid == pid &&
memcmp(&shares[i].time,
&fsp->open_time,sizeof(struct timeval)) == 0) {
+ *ppse = memdup(&shares[i], sizeof(*shares));
data->num_share_mode_entries--;
memmove(&shares[i], &shares[i+1],
dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
@@ -366,6 +372,8 @@ void del_share_mode(files_struct *fsp)
/* the record has shrunk a bit */
dbuf.dsize -= del_count * sizeof(*shares);
+ count = data->num_share_mode_entries;
+
/* store it back in the database */
if (data->num_share_mode_entries == 0) {
tdb_delete(tdb, locking_key_fsp(fsp));
@@ -374,6 +382,7 @@ void del_share_mode(files_struct *fsp)
}
free(dbuf.dptr);
+ return count;
}
/*******************************************************************
@@ -529,42 +538,40 @@ BOOL downgrade_share_oplock(files_struct *fsp)
return mod_share_mode(fsp, downgrade_share_oplock_fn, NULL);
}
-
/*******************************************************************
- Static function that actually does the work for the generic function
- below.
+ Get/Set the delete on close flag in a set of share modes.
+ Return False on fail, True on success.
********************************************************************/
-struct mod_val {
- int new_share_mode;
- uint16 new_oplock;
-};
-static void modify_share_mode_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode,
- void *param)
+BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close)
{
- struct mod_val *mvp = (struct mod_val *)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, mvp->new_share_mode, (unsigned int)dev, (double)inode ));
- DEBUG(10,("modify_share_mode_fn: changing oplock state from %x to %x for entry dev=%x ino=%.0f\n",
- entry->op_type, (int)mvp->new_oplock, (unsigned int)dev, (double)inode ));
- /* Change the share mode info. */
- entry->share_mode = mvp->new_share_mode;
- entry->op_type = mvp->new_oplock;
-}
+ TDB_DATA dbuf;
+ struct locking_data *data;
+ int i;
+ share_mode_entry *shares;
-/*******************************************************************
- 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(files_struct *fsp, int new_mode, uint16 new_oplock)
-{
- struct mod_val mv;
+ /* read in the existing share modes */
+ dbuf = tdb_fetch(tdb, locking_key(dev, inode));
+ if (!dbuf.dptr) return False;
+
+ data = (struct locking_data *)dbuf.dptr;
+ shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
- mv.new_share_mode = new_mode;
- mv.new_oplock = new_oplock;
+ /* Set/Unset the delete on close element. */
+ for (i=0;i<data->num_share_mode_entries;i++,shares++) {
+ shares->share_mode = (delete_on_close ?
+ (shares->share_mode | DELETE_ON_CLOSE_FLAG) :
+ (shares->share_mode & ~DELETE_ON_CLOSE_FLAG) );
+ }
- return mod_share_mode(fsp, modify_share_mode_fn, (void *)&mv);
+ /* store it back */
+ if (data->num_share_mode_entries) {
+ if (tdb_store(tdb, locking_key(dev,inode), dbuf, TDB_REPLACE)==-1)
+ return False;
+ }
+
+ free(dbuf.dptr);
+ return True;
}
diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index 56aad643914..c290ee6f894 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -99,7 +99,9 @@ static int close_filestruct(files_struct *fsp)
static int close_normal_file(files_struct *fsp, BOOL normal_close)
{
- BOOL delete_on_close = fsp->delete_on_close;
+ share_mode_entry *share_entry = NULL;
+ size_t share_entry_count = 0;
+ BOOL delete_on_close = False;
connection_struct *conn = fsp->conn;
int err = 0;
int err1 = 0;
@@ -120,21 +122,25 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
return 0;
}
- lock_share_entry_fsp(fsp);
- del_share_mode(fsp);
- unlock_share_entry_fsp(fsp);
+ /*
+ * Lock the share entries, and determine if we should delete
+ * on close. If so delete whilst the lock is still in effect.
+ * This prevents race conditions with the file being created. JRA.
+ */
- if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
- release_file_oplock(fsp);
+ lock_share_entry_fsp(fsp);
+ share_entry_count = del_share_mode(fsp, &share_entry);
- locking_close_file(fsp);
+ /*
+ * We delete on close if it's the last open, and the
+ * delete on close flag was set in the entry we just deleted.
+ */
- err = fd_close(conn, fsp);
+ if ((share_entry_count == 0) && share_entry &&
+ GET_DELETE_ON_CLOSE_FLAG(share_entry->share_mode) )
+ delete_on_close = True;
- /* check for magic scripts */
- if (normal_close) {
- check_magic(fsp,conn);
- }
+ safe_free(share_entry);
/*
* NT can set delete_on_close of the last open
@@ -157,6 +163,21 @@ with error %s\n", fsp->fsp_name, strerror(errno) ));
}
}
+ unlock_share_entry_fsp(fsp);
+
+ if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
+ release_file_oplock(fsp);
+
+ locking_close_file(fsp);
+
+ err = fd_close(conn, fsp);
+
+ /* check for magic scripts */
+ if (normal_close) {
+ check_magic(fsp,conn);
+ }
+
+
DEBUG(2,("%s closed file %s (numopen=%d) %s\n",
conn->user,fsp->fsp_name,
conn->num_files_open, err ? strerror(err) : ""));
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 58b484f44d6..b67815ff694 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -47,6 +47,15 @@ static char *known_nt_pipes[] = {
NULL
};
+/* Map generic permissions to file object specific permissions */
+
+struct generic_mapping file_generic_mapping = {
+ FILE_GENERIC_READ,
+ FILE_GENERIC_WRITE,
+ FILE_GENERIC_EXECUTE,
+ FILE_GENERIC_ALL
+};
+
/****************************************************************************
Send the required number of replies back.
We assume all fields other than the data fields are
@@ -332,6 +341,12 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname,
*pstat_open_only = False;
+ /*
+ * Convert GENERIC bits to specific bits.
+ */
+
+ se_map_generic(&desired_access, &file_generic_mapping);
+
switch( desired_access & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA) ) {
case FILE_READ_DATA:
smb_open_mode = DOS_OPEN_RDONLY;
@@ -395,8 +410,22 @@ static int map_share_mode( BOOL *pstat_open_only, char *fname,
* JRA.
*/
- if(share_access & FILE_SHARE_DELETE)
+ if(share_access & FILE_SHARE_DELETE) {
smb_open_mode |= ALLOW_SHARE_DELETE;
+ DEBUG(10,("map_share_mode: FILE_SHARE_DELETE requested. open_mode = %x\n", smb_open_mode));
+ }
+
+ /*
+ * We need to store the intent to open for Delete. This
+ * is what determines if a delete on close flag can be set.
+ * This is the wrong way (and place) to store this, but for 2.2 this
+ * is the only practical way. JRA.
+ */
+
+ if(desired_access & DELETE_ACCESS) {
+ smb_open_mode |= DELETE_ACCESS_REQUESTED;
+ DEBUG(10,("map_share_mode: DELETE_ACCESS requested. open_mode = %x\n", smb_open_mode));
+ }
/* Add in the requested share mode. */
switch( share_access & (FILE_SHARE_READ|FILE_SHARE_WRITE)) {
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index c6011214599..5f8657262a2 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -341,18 +341,19 @@ static int access_table(int new_deny,int old_deny,int old_mode,
check if we can open a file with a share mode
****************************************************************************/
-static int check_share_mode( share_mode_entry *share, int deny_mode,
+static int check_share_mode( share_mode_entry *share, int share_mode,
const char *fname, BOOL fcbopen, int *flags)
{
+ int deny_mode = GET_DENY_MODE(share_mode);
int old_open_mode = GET_OPEN_MODE(share->share_mode);
int old_deny_mode = GET_DENY_MODE(share->share_mode);
/*
- * Don't allow any open once the delete on close flag has been
+ * Don't allow any opens once the delete on close flag has been
* set.
*/
- if(GET_DELETE_ON_CLOSE_FLAG(share->share_mode)) {
+ 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_class = ERRDOS;
@@ -360,6 +361,35 @@ static int check_share_mode( share_mode_entry *share, int deny_mode,
return False;
}
+ /*
+ * If delete access was requested and the existing share mode doesn't have
+ * ALLOW_SHARE_DELETE then deny.
+ */
+
+ if (GET_DELETE_ACCESS_REQUESTED(share_mode) && !GET_ALLOW_SHARE_DELETE(share->share_mode)) {
+ DEBUG(5,("check_share_mode: Failing open on file %s as delete access requested and allow share delete not set.\n",
+ fname ));
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+
+ return False;
+ }
+
+ /*
+ * The inverse of the above.
+ * If delete access was granted and the new share mode doesn't have
+ * ALLOW_SHARE_DELETE then deny.
+ */
+
+ if (GET_DELETE_ACCESS_REQUESTED(share->share_mode) && !GET_ALLOW_SHARE_DELETE(share_mode)) {
+ DEBUG(5,("check_share_mode: Failing open on file %s as delete access granted and allow share delete not requested.\n",
+ fname ));
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadshare;
+
+ return False;
+ }
+
{
int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode,
(share->pid == sys_getpid()),is_executable(fname));
@@ -405,7 +435,6 @@ static int open_mode_check(connection_struct *conn, const char *fname, SMB_DEV_T
int oplock_contention_count = 0;
share_mode_entry *old_shares = 0;
BOOL fcbopen = False;
- int deny_mode = GET_DENY_MODE(share_mode);
BOOL broke_oplock;
if(GET_OPEN_MODE(share_mode) == DOS_OPEN_FCB)
@@ -473,7 +502,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
/* someone else has a share lock on it, check to see
if we can too */
- if(check_share_mode(share_entry, deny_mode, fname, fcbopen, p_flags) == False) {
+ if(check_share_mode(share_entry, share_mode, fname, fcbopen, p_flags) == False) {
free((char *)old_shares);
errno = EACCES;
return -1;
@@ -532,6 +561,7 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S
int flags2=0;
int deny_mode = GET_DENY_MODE(share_mode);
BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE(share_mode);
+ BOOL delete_access_requested = GET_DELETE_ACCESS_REQUESTED(share_mode);
BOOL file_existed = VALID_STAT(*psbuf);
BOOL fcbopen = False;
SMB_DEV_T dev = 0;
@@ -768,7 +798,10 @@ files_struct *open_file_shared(connection_struct *conn,char *fname, SMB_STRUCT_S
fsp->share_mode = SET_DENY_MODE(deny_mode) |
SET_OPEN_MODE(open_mode) |
- SET_ALLOW_SHARE_DELETE(allow_share_delete);
+ SET_ALLOW_SHARE_DELETE(allow_share_delete) |
+ SET_DELETE_ACCESS_REQUESTED(delete_access_requested);
+
+ DEBUG(10,("open_file_shared : share_mode = %x\n", fsp->share_mode ));
if (Access)
(*Access) = open_mode;
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 5b0c22c77e5..aa8f9376c76 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -559,6 +559,7 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
SEC_ACL *dacl)
{
extern DOM_SID global_sid_World;
+ extern struct generic_mapping *file_generic_mapping;
BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
canon_ace *file_ace = NULL;
canon_ace *dir_ace = NULL;
@@ -589,8 +590,13 @@ static BOOL create_canon_ace_lists(files_struct *fsp,
* to be so. Any other bits override the UNIX_ACCESS_NONE bit.
*/
- psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
- GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
+ /*
+ * Convert GENERIC bits to specific bits.
+ */
+
+ se_map_generic(&psa->info.mask, &file_generic_mapping);
+
+ psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
if(psa->info.mask != UNIX_ACCESS_NONE)
psa->info.mask &= ~UNIX_ACCESS_NONE;
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 5a7a5c72cb1..be130247c0e 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. */