diff options
author | Gerald Carter <jerry@samba.org> | 2005-09-30 17:13:37 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:04:48 -0500 |
commit | 54abd2aa66069e6baf7769c496f46d9dba18db39 (patch) | |
tree | 9cf8e88168011797319ba9e9866749201b1eac1e /source3/locking | |
parent | 4a2cc231d22a82ed21771a72508f15d21ed63227 (diff) | |
download | samba-54abd2aa66069e6baf7769c496f46d9dba18db39.tar.gz samba-54abd2aa66069e6baf7769c496f46d9dba18db39.tar.bz2 samba-54abd2aa66069e6baf7769c496f46d9dba18db39.zip |
r10656: BIG merge from trunk. Features not copied over
* \PIPE\unixinfo
* winbindd's {group,alias}membership new functions
* winbindd's lookupsids() functionality
* swat (trunk changes to be reverted as per discussion with Deryck)
(This used to be commit 939c3cb5d78e3a2236209b296aa8aba8bdce32d3)
Diffstat (limited to 'source3/locking')
-rw-r--r-- | source3/locking/brlock.c | 24 | ||||
-rw-r--r-- | source3/locking/locking.c | 1204 |
2 files changed, 467 insertions, 761 deletions
diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c index da7fc1e67d..25a1ed5e2f 100644 --- a/source3/locking/brlock.c +++ b/source3/locking/brlock.c @@ -39,7 +39,7 @@ struct lock_context { uint16 smbpid; uint16 tid; - pid_t pid; + struct process_id pid; }; /* The data in brlock records is an unsorted linear array of these @@ -89,9 +89,9 @@ static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode) static BOOL brl_same_context(struct lock_context *ctx1, struct lock_context *ctx2) { - return (ctx1->pid == ctx2->pid) && + return (procid_equal(&ctx1->pid, &ctx2->pid) && (ctx1->smbpid == ctx2->smbpid) && - (ctx1->tid == ctx2->tid); + (ctx1->tid == ctx2->tid)); } /**************************************************************************** @@ -252,7 +252,7 @@ static int delete_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *stat DEBUG(0,("brlock : delete_fn. LOGIC ERROR ! Shutting down and a record for my pid (%u) exists !\n", (unsigned int)lock->context.pid )); - } else if (process_exists(lock->context.pid)) { + } else if (process_exists(&lock->context.pid)) { DEBUG(10,("brlock : delete_fn. pid %u exists.\n", (unsigned int)lock->context.pid )); continue; @@ -347,7 +347,7 @@ static int lock_compare(struct lock_struct *lck1, ****************************************************************************/ NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, - uint16 smbpid, pid_t pid, uint16 tid, + uint16 smbpid, struct process_id pid, uint16 tid, br_off start, br_off size, enum brl_type lock_type, BOOL *my_lock_ctx) { @@ -450,7 +450,7 @@ static BOOL brl_pending_overlap(struct lock_struct *lock, struct lock_struct *pe ****************************************************************************/ BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, - uint16 smbpid, pid_t pid, uint16 tid, + uint16 smbpid, struct process_id pid, uint16 tid, br_off start, br_off size, BOOL remove_pending_locks_only, void (*pre_unlock_fn)(void *), @@ -542,8 +542,8 @@ BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, /* We could send specific lock info here... */ if (brl_pending_overlap(lock, pend_lock)) { - DEBUG(10,("brl_unlock: sending unlock message to pid %u\n", - (unsigned int)pend_lock->context.pid )); + DEBUG(10,("brl_unlock: sending unlock message to pid %s\n", + procid_str_static(&pend_lock->context.pid ))); message_send_pid(pend_lock->context.pid, MSG_SMB_UNLOCK, @@ -584,7 +584,7 @@ BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, ****************************************************************************/ BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum, - uint16 smbpid, pid_t pid, uint16 tid, + uint16 smbpid, struct process_id pid, uint16 tid, br_off start, br_off size, enum brl_type lock_type) { @@ -632,7 +632,7 @@ BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum, Remove any locks associated with a open file. ****************************************************************************/ -void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum) +void brl_close(SMB_DEV_T dev, SMB_INO_T ino, struct process_id pid, int tid, int fnum) { TDB_DATA kbuf, dbuf; int count, i, j, dcount=0; @@ -655,7 +655,7 @@ void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum) struct lock_struct *lock = &locks[i]; if (lock->context.tid == tid && - lock->context.pid == pid && + procid_equal(&lock->context.pid, &pid) && lock->fnum == fnum) { /* Send unlock messages to any pending waiters that overlap. */ @@ -667,7 +667,7 @@ void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum) continue; if (pend_lock->context.tid == tid && - pend_lock->context.pid == pid && + procid_equal(&pend_lock->context.pid, &pid) && pend_lock->fnum == fnum) continue; diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 5bcf7f2eda..e3131e26a2 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -43,7 +43,6 @@ uint16 global_smbpid; /* the locking database handle */ static TDB_CONTEXT *tdb; -static TDB_CONTEXT *deferred_open_tdb; struct locking_data { union { @@ -51,10 +50,10 @@ struct locking_data { int num_share_mode_entries; BOOL delete_on_close; } s; - share_mode_entry dummy; /* Needed for alignment. */ + struct share_mode_entry dummy; /* Needed for alignment. */ } u; /* the following two entries are implicit - share_mode_entry modes[num_share_mode_entries]; + struct share_mode_entry modes[num_share_mode_entries]; char file_name[]; */ }; @@ -90,17 +89,18 @@ BOOL is_locked(files_struct *fsp,connection_struct *conn, if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && (lock_type == READ_LOCK || lock_type == WRITE_LOCK)) { DEBUG(10,("is_locked: optimisation - exclusive oplock on file %s\n", fsp->fsp_name )); ret = 0; - } else if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type) && (lock_type == READ_LOCK)) { + } else if ((fsp->oplock_type == LEVEL_II_OPLOCK) && + (lock_type == READ_LOCK)) { DEBUG(10,("is_locked: optimisation - level II oplock on file %s\n", fsp->fsp_name )); ret = 0; } else { ret = !brl_locktest(fsp->dev, fsp->inode, fsp->fnum, - global_smbpid, sys_getpid(), conn->cnum, + global_smbpid, procid_self(), conn->cnum, offset, count, lock_type); } } else { ret = !brl_locktest(fsp->dev, fsp->inode, fsp->fnum, - global_smbpid, sys_getpid(), conn->cnum, + global_smbpid, procid_self(), conn->cnum, offset, count, lock_type); } @@ -143,7 +143,7 @@ static NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_p if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn)) { status = brl_lock(fsp->dev, fsp->inode, fsp->fnum, - lock_pid, sys_getpid(), conn->cnum, + lock_pid, procid_self(), conn->cnum, offset, count, lock_type, my_lock_ctx); @@ -166,7 +166,7 @@ static NTSTATUS do_lock(files_struct *fsp,connection_struct *conn, uint16 lock_p * lock entry. */ (void)brl_unlock(fsp->dev, fsp->inode, fsp->fnum, - lock_pid, sys_getpid(), conn->cnum, + lock_pid, procid_self(), conn->cnum, offset, count, False, NULL, NULL); } @@ -264,7 +264,7 @@ NTSTATUS do_unlock(files_struct *fsp,connection_struct *conn, uint16 lock_pid, posix_data.count = count; ok = brl_unlock(fsp->dev, fsp->inode, fsp->fnum, - lock_pid, sys_getpid(), conn->cnum, offset, count, + lock_pid, procid_self(), conn->cnum, offset, count, False, posix_unlock, (void *)&posix_data); if (!ok) { @@ -280,7 +280,7 @@ NTSTATUS do_unlock(files_struct *fsp,connection_struct *conn, uint16 lock_pid, void locking_close_file(files_struct *fsp) { - pid_t pid = sys_getpid(); + struct process_id pid = procid_self(); if (!lp_locking(SNUM(fsp->conn))) return; @@ -324,20 +324,6 @@ BOOL locking_init(int read_only) return False; } - if (!read_only && !deferred_open_tdb) { - deferred_open_tdb = tdb_open_log(lock_path("deferred_open.tdb"), - 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST, - O_RDWR|O_CREAT, - 0644); - - if (!deferred_open_tdb) { - DEBUG(0,("ERROR: Failed to initialise deferred open database\n")); - tdb_close(tdb); - tdb = NULL; - return False; - } - } - if (!posix_locking_init(read_only)) return False; @@ -360,11 +346,6 @@ BOOL locking_end(void) ret = False; } - if (deferred_open_tdb) { - if (tdb_close(deferred_open_tdb) != 0) - ret = False; - } - return ret; } @@ -372,6 +353,16 @@ BOOL locking_end(void) Form a static locking key for a dev/inode pair. ******************************************************************/ +/* key and data records in the tdb locking database */ +struct locking_key { + SMB_DEV_T dev; + SMB_INO_T ino; +}; + +/******************************************************************* + Form a static locking key for a dev/inode pair. +******************************************************************/ + static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode) { static struct locking_key key; @@ -379,70 +370,27 @@ static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode) memset(&key, '\0', sizeof(key)); key.dev = dev; - key.inode = inode; + key.ino = inode; kbuf.dptr = (char *)&key; kbuf.dsize = sizeof(key); return kbuf; } -static TDB_DATA locking_key_fsp(files_struct *fsp) -{ - return locking_key(fsp->dev, fsp->inode); -} - -/******************************************************************* - Lock a hash bucket entry. -******************************************************************/ - -BOOL lock_share_entry(connection_struct *conn, - SMB_DEV_T dev, SMB_INO_T inode) -{ - return tdb_chainlock(tdb, locking_key(dev, inode)) == 0; -} - -/******************************************************************* - Unlock a hash bucket entry. -******************************************************************/ - -void unlock_share_entry(connection_struct *conn, - SMB_DEV_T dev, SMB_INO_T inode) -{ - tdb_chainunlock(tdb, locking_key(dev, inode)); -} - -/******************************************************************* - Lock a hash bucket entry. use a fsp for convenience -******************************************************************/ - -BOOL lock_share_entry_fsp(files_struct *fsp) -{ - return tdb_chainlock(tdb, locking_key(fsp->dev, fsp->inode)) == 0; -} - -/******************************************************************* - Unlock a hash bucket entry. -******************************************************************/ - -void unlock_share_entry_fsp(files_struct *fsp) -{ - tdb_chainunlock(tdb, locking_key(fsp->dev, fsp->inode)); -} - /******************************************************************* Print out a share mode. ********************************************************************/ -char *share_mode_str(int num, share_mode_entry *e) +char *share_mode_str(int num, struct share_mode_entry *e) { static pstring share_str; slprintf(share_str, sizeof(share_str)-1, "share_mode_entry[%d]: " - "pid = %lu, share_access = 0x%x, private_options = 0x%x, " - "access_mask = 0x%x, port = 0x%x, type= 0x%x, file_id = %lu, " + "pid = %s, share_access = 0x%x, private_options = 0x%x, " + "access_mask = 0x%x, mid = 0x%x, type= 0x%x, file_id = %lu, " "dev = 0x%x, inode = %.0f", - num, (unsigned long)e->pid, + num, procid_str_static(&e->pid), e->share_access, e->private_options, - e->access_mask, e->op_port, e->op_type, e->share_file_id, + e->access_mask, e->op_mid, e->op_type, e->share_file_id, (unsigned int)e->dev, (double)e->inode ); return share_str; @@ -455,12 +403,14 @@ char *share_mode_str(int num, share_mode_entry *e) static void print_share_mode_table(struct locking_data *data) { int num_share_modes = data->u.s.num_share_mode_entries; - share_mode_entry *shares = (share_mode_entry *)(data + 1); + struct share_mode_entry *shares = + (struct share_mode_entry *)(data + 1); int i; for (i = 0; i < num_share_modes; i++) { - share_mode_entry *entry_p = &shares[i]; - DEBUG(10,("print_share_mode_table: %s\n", share_mode_str(i, entry_p) )); + struct share_mode_entry *entry_p = &shares[i]; + DEBUG(10,("print_share_mode_table: %s\n", + share_mode_str(i, entry_p))); } } @@ -468,825 +418,581 @@ static void print_share_mode_table(struct locking_data *data) Get all share mode entries for a dev/inode pair. ********************************************************************/ -int get_share_modes(SMB_DEV_T dev, SMB_INO_T inode, - share_mode_entry **pp_shares, - BOOL *delete_on_close) +static BOOL parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) { - TDB_DATA dbuf; struct locking_data *data; - int num_share_modes; - share_mode_entry *shares = NULL; - TDB_DATA key = locking_key(dev, inode); - *pp_shares = NULL; - *delete_on_close = False; - - dbuf = tdb_fetch(tdb, key); - if (!dbuf.dptr) - return 0; - - data = (struct locking_data *)dbuf.dptr; + int i; - *delete_on_close = data->u.s.delete_on_close; - DEBUG(10, ("get_share_modes: delete_on_close: %d\n", - *delete_on_close)); - num_share_modes = data->u.s.num_share_mode_entries; - if(num_share_modes) { - pstring fname; - int i; - int del_count = 0; - - shares = (share_mode_entry *)memdup(dbuf.dptr + sizeof(*data), - num_share_modes * sizeof(share_mode_entry)); - - if (!shares) { - SAFE_FREE(dbuf.dptr); - return 0; - } + if (dbuf.dsize < sizeof(struct locking_data)) { + DEBUG(0, ("parse_share_modes: buffer too short\n")); + return False; + } - /* Save off the associated filename. */ - pstrcpy(fname, dbuf.dptr + sizeof(*data) + num_share_modes * sizeof(share_mode_entry)); + data = (struct locking_data *)dbuf.dptr; - /* - * Ensure that each entry has a real process attached. - */ + lck->delete_on_close = data->u.s.delete_on_close; + lck->num_share_modes = data->u.s.num_share_mode_entries; - for (i = 0; i < num_share_modes; ) { - share_mode_entry *entry_p = &shares[i]; - if (process_exists(entry_p->pid)) { - DEBUG(10,("get_share_modes: %s\n", share_mode_str(i, entry_p) )); - i++; - } else { - DEBUG(10,("get_share_modes: deleted %s\n", share_mode_str(i, entry_p) )); - if (num_share_modes - i - 1 > 0) { - memcpy( &shares[i], &shares[i+1], - sizeof(share_mode_entry) * (num_share_modes - i - 1)); - } - num_share_modes--; - del_count++; - } - } + DEBUG(10, ("parse_share_modes: delete_on_close: %d, " + "num_share_modes: %d\n", lck->delete_on_close, + lck->num_share_modes)); - /* Did we delete any ? If so, re-store in tdb. */ - if (del_count) { - data->u.s.num_share_mode_entries = num_share_modes; - - if (num_share_modes) { - memcpy(dbuf.dptr + sizeof(*data), shares, - num_share_modes * sizeof(share_mode_entry)); - /* Append the filename. */ - pstrcpy(dbuf.dptr + sizeof(*data) + num_share_modes * sizeof(share_mode_entry), fname); - } - - /* The record has shrunk a bit */ - dbuf.dsize -= del_count * sizeof(share_mode_entry); - - if (data->u.s.num_share_mode_entries == 0) { - if (tdb_delete(tdb, key) == -1) { - SAFE_FREE(shares); - SAFE_FREE(dbuf.dptr); - return 0; - } - } else { - if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) { - SAFE_FREE(shares); - SAFE_FREE(dbuf.dptr); - return 0; - } - } - } + if ((lck->num_share_modes < 0) || (lck->num_share_modes > 1000000)) { + DEBUG(0, ("invalid number of share modes: %d\n", + lck->num_share_modes)); + return False; } - SAFE_FREE(dbuf.dptr); - *pp_shares = shares; - return num_share_modes; -} + lck->share_modes = NULL; -BOOL get_delete_on_close_flag(SMB_DEV_T dev, SMB_INO_T inode) -{ - share_mode_entry *shares; - BOOL result; - get_share_modes(dev, inode, &shares, &result); - SAFE_FREE(shares); - return result; -} + if (lck->num_share_modes != 0) { -/******************************************************************* - Fill a share mode entry. -********************************************************************/ + if (dbuf.dsize < (sizeof(struct locking_data) + + (lck->num_share_modes * + sizeof(struct share_mode_entry)))) { + DEBUG(0, ("parse_share_modes: buffer too short\n")); + return False; + } + + lck->share_modes = talloc_memdup(lck, dbuf.dptr+sizeof(*data), + lck->num_share_modes * + sizeof(struct share_mode_entry)); -static void fill_share_mode(char *p, files_struct *fsp, uint16 port, uint16 op_type) -{ - share_mode_entry *e = (share_mode_entry *)p; - void *x = &e->time; /* Needed to force alignment. p may not be aligned.... */ + if (lck->share_modes == NULL) { + DEBUG(0, ("talloc failed\n")); + return False; + } + } - memset(e, '\0', sizeof(share_mode_entry)); - e->pid = sys_getpid(); - e->share_access = fsp->share_access; - e->private_options = fsp->fh->private_options; - e->access_mask = fsp->access_mask; - e->op_port = port; - e->op_type = op_type; - memcpy(x, &fsp->open_time, sizeof(struct timeval)); - e->share_file_id = fsp->file_id; - e->dev = fsp->dev; - e->inode = fsp->inode; -} + /* Save off the associated filename. */ + lck->filename = talloc_strdup(lck, dbuf.dptr + sizeof(*data) + + lck->num_share_modes * + sizeof(struct share_mode_entry)); -/******************************************************************* - Check if two share mode entries are identical, ignoring oplock - and port info and desired_access. -********************************************************************/ + /* + * Ensure that each entry has a real process attached. + */ -BOOL share_modes_identical( share_mode_entry *e1, share_mode_entry *e2) -{ -#if 1 /* JRA PARANOIA TEST - REMOVE LATER */ - if (e1->pid == e2->pid && - e1->share_file_id == e2->share_file_id && - e1->dev == e2->dev && - e1->inode == e2->inode && - (e1->share_access) != (e2->share_access)) { - DEBUG(0,("PANIC: share_modes_identical: share_mode " - "mismatch (e1 = 0x%x, e2 = 0x%x). Logic error.\n", - (unsigned int)e1->share_access, - (unsigned int)e2->share_access )); - smb_panic("PANIC: share_modes_identical logic error.\n"); + for (i = 0; i < lck->num_share_modes; i++) { + struct share_mode_entry *entry_p = &lck->share_modes[i]; + DEBUG(10,("parse_share_modes: %s\n", + share_mode_str(i, entry_p) )); + if (!process_exists(entry_p->pid)) { + DEBUG(10,("parse_share_modes: deleted %s\n", + share_mode_str(i, entry_p) )); + entry_p->op_type = UNUSED_SHARE_MODE_ENTRY; + lck->modified = True; + } } -#endif - return (e1->pid == e2->pid && - (e1->share_access) == (e2->share_access) && - e1->dev == e2->dev && - e1->inode == e2->inode && - e1->share_file_id == e2->share_file_id ); + return True; } -/******************************************************************* - Delete a specific share mode. Return the number - of entries left, and a memdup'ed copy of the entry deleted (if required). - Ignore if no entry deleted. -********************************************************************/ - -ssize_t del_share_entry(SMB_DEV_T dev, SMB_INO_T inode, - share_mode_entry *entry, share_mode_entry **ppse, - BOOL *delete_on_close) +static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) { - TDB_DATA dbuf; + TDB_DATA result; + int num_valid = 0; + int i; struct locking_data *data; - int i, del_count=0; - share_mode_entry *shares; - ssize_t count = 0; - TDB_DATA key = locking_key(dev, inode); - - if (ppse) - *ppse = NULL; - - /* read in the existing share modes */ - dbuf = tdb_fetch(tdb, key); - if (!dbuf.dptr) - return -1; - - data = (struct locking_data *)dbuf.dptr; - *delete_on_close = data->u.s.delete_on_close; - shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data)); - - /* - * Find any with this pid and delete it - * by overwriting with the rest of the data - * from the record. - */ - - DEBUG(10,("del_share_entry: num_share_modes = %d\n", data->u.s.num_share_mode_entries )); - - for (i=0;i<data->u.s.num_share_mode_entries;) { - if (share_modes_identical(&shares[i], entry)) { - DEBUG(10,("del_share_entry: deleted %s\n", - share_mode_str(i, &shares[i]) )); - if (ppse) - *ppse = memdup(&shares[i], sizeof(*shares)); - data->u.s.num_share_mode_entries--; - if ((dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares))) > 0) { - memmove(&shares[i], &shares[i+1], - dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares))); - } - del_count++; + ssize_t offset; - DEBUG(10,("del_share_entry: deleting entry %d\n", i )); + result.dptr = NULL; + result.dsize = 0; - } else { - i++; + for (i=0; i<lck->num_share_modes; i++) { + if (!is_unused_share_mode_entry(&lck->share_modes[i])) { + num_valid += 1; } } - if (del_count) { - /* the record may have shrunk a bit */ - dbuf.dsize -= del_count * sizeof(*shares); - - count = (ssize_t)data->u.s.num_share_mode_entries; - - /* store it back in the database */ - if (data->u.s.num_share_mode_entries == 0) { - if (tdb_delete(tdb, key) == -1) - count = -1; - } else { - if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) - count = -1; - } + if (num_valid == 0) { + return result; } - DEBUG(10,("del_share_entry: Remaining table.\n")); - print_share_mode_table((struct locking_data *)dbuf.dptr); - SAFE_FREE(dbuf.dptr); - return count; -} -/******************************************************************* - 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. -********************************************************************/ - -ssize_t del_share_mode(files_struct *fsp, share_mode_entry **ppse, - BOOL *delete_on_close) -{ - share_mode_entry entry; + result.dsize = sizeof(*data) + + lck->num_share_modes * sizeof(struct share_mode_entry) + + strlen(lck->filename) + 1; + result.dptr = talloc_size(lck, result.dsize); - /* - * Fake up a share_mode_entry for comparisons. - */ + if (result.dptr == NULL) { + smb_panic("talloc failed\n"); + } - fill_share_mode((char *)&entry, fsp, 0, 0); - return del_share_entry(fsp->dev, fsp->inode, &entry, ppse, - delete_on_close); + data = (struct locking_data *)result.dptr; + ZERO_STRUCTP(data); + data->u.s.num_share_mode_entries = lck->num_share_modes; + data->u.s.delete_on_close = lck->delete_on_close; + DEBUG(10, ("unparse_share_modes: del: %d, num: %d\n", + data->u.s.delete_on_close, + data->u.s.num_share_mode_entries)); + memcpy(result.dptr + sizeof(*data), lck->share_modes, + sizeof(struct share_mode_entry)*lck->num_share_modes); + offset = sizeof(*data) + + sizeof(struct share_mode_entry)*lck->num_share_modes; + safe_strcpy(result.dptr + offset, lck->filename, + result.dsize - offset - 1); + print_share_mode_table(data); + return result; } -/******************************************************************* - Set the share mode of a file. Return False on fail, True on success. -********************************************************************/ - -BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type) +static int share_mode_lock_destructor(void *p) { - TDB_DATA dbuf; - struct locking_data *data; - char *p=NULL; - int size; - TDB_DATA key = locking_key_fsp(fsp); - BOOL ret = True; - - /* read in the existing share modes if any */ - dbuf = tdb_fetch(tdb, key); - if (!dbuf.dptr) { - size_t offset; - /* we'll need to create a new record */ - pstring fname; - - pstrcpy(fname, fsp->conn->connectpath); - pstrcat(fname, "/"); - pstrcat(fname, fsp->fsp_name); - - size = sizeof(*data) + sizeof(share_mode_entry) + strlen(fname) + 1; - p = (char *)SMB_MALLOC(size); - if (!p) - return False; - data = (struct locking_data *)p; - ZERO_STRUCT(data->u); /* Keep valgrind happy */ - data->u.s.num_share_mode_entries = 1; - - DEBUG(10,("set_share_mode: creating entry for file %s. num_share_modes = 1\n", - fsp->fsp_name )); + struct share_mode_lock *lck = + talloc_get_type_abort(p, struct share_mode_lock); + TDB_DATA key = locking_key(lck->dev, lck->ino); + TDB_DATA data; - offset = sizeof(*data) + sizeof(share_mode_entry); - safe_strcpy(p + offset, fname, size - offset - 1); - fill_share_mode(p + sizeof(*data), fsp, port, op_type); - dbuf.dptr = p; - dbuf.dsize = size; - if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) - ret = False; + if (!lck->modified) { + goto done; + } - print_share_mode_table((struct locking_data *)p); + data = unparse_share_modes(lck); - SAFE_FREE(p); - return ret; + if (data.dptr == NULL) { + if (!lck->fresh) { + /* There has been an entry before, delete it */ + if (tdb_delete(tdb, key) == -1) { + smb_panic("Could not delete share entry\n"); + } + } + goto done; } - /* we're adding to an existing entry - this is a bit fiddly */ - data = (struct locking_data *)dbuf.dptr; + if (tdb_store(tdb, key, data, TDB_REPLACE) == -1) { + smb_panic("Could not store share mode entry\n"); + } - data->u.s.num_share_mode_entries++; - - DEBUG(10,("set_share_mode: adding entry for file %s. new num_share_modes = %d\n", - fsp->fsp_name, data->u.s.num_share_mode_entries )); + done: + tdb_chainunlock(tdb, key); - size = dbuf.dsize + sizeof(share_mode_entry); - p = SMB_MALLOC(size); - if (!p) { - SAFE_FREE(dbuf.dptr); - return False; - } - memcpy(p, dbuf.dptr, sizeof(*data)); - fill_share_mode(p + sizeof(*data), fsp, port, op_type); - memcpy(p + sizeof(*data) + sizeof(share_mode_entry), dbuf.dptr + sizeof(*data), - dbuf.dsize - sizeof(*data)); - SAFE_FREE(dbuf.dptr); - dbuf.dptr = p; - dbuf.dsize = size; - if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) - ret = False; - print_share_mode_table((struct locking_data *)p); - SAFE_FREE(p); - return ret; + return 0; } -/******************************************************************* - A generic in-place modification call for share mode entries. -********************************************************************/ - -static BOOL mod_share_mode( SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry *entry, - void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *), - void *param) +struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, + SMB_DEV_T dev, SMB_INO_T ino, + const char *fname) { - TDB_DATA dbuf; - struct locking_data *data; - int i; - share_mode_entry *shares; - BOOL need_store=False; - BOOL ret = True; - TDB_DATA key = locking_key(dev, inode); - - /* read in the existing share modes */ - dbuf = tdb_fetch(tdb, key); - if (!dbuf.dptr) - return False; + struct share_mode_lock *lck; + TDB_DATA key = locking_key(dev, ino); + TDB_DATA data; - data = (struct locking_data *)dbuf.dptr; - shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data)); + lck = TALLOC_P(mem_ctx, struct share_mode_lock); + if (lck == NULL) { + DEBUG(0, ("talloc failed\n")); + return NULL; + } - /* find any with our pid and call the supplied function */ - for (i=0;i<data->u.s.num_share_mode_entries;i++) { - if (share_modes_identical(entry, &shares[i])) { - mod_fn(&shares[i], dev, inode, param); - need_store=True; - } + lck->dev = dev; + lck->ino = ino; + lck->delete_on_close = False; + lck->num_share_modes = 0; + lck->share_modes = NULL; + lck->modified = False; + + if (tdb_chainlock(tdb, key) != 0) { + DEBUG(3, ("Could not lock share entry\n")); + talloc_free(lck); + return NULL; } - /* if the mod fn was called then store it back */ - if (need_store) { - if (data->u.s.num_share_mode_entries == 0) { - if (tdb_delete(tdb, key) == -1) - ret = False; - } else { - if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) - ret = False; + data = tdb_fetch(tdb, key); + lck->fresh = (data.dptr == NULL); + + if (lck->fresh) { + if (fname == NULL) { + DEBUG(0, ("New file, but no filename supplied\n")); + talloc_free(lck); + return NULL; + } + lck->filename = talloc_strdup(lck, fname); + if (lck->filename == NULL) { + DEBUG(0, ("talloc failed\n")); + talloc_free(lck); + return NULL; + } + } else { + if (!parse_share_modes(data, lck)) { + DEBUG(0, ("Could not parse share modes\n")); + talloc_free(lck); + SAFE_FREE(data.dptr); + return NULL; } } - SAFE_FREE(dbuf.dptr); - return ret; -} + talloc_set_destructor(lck, share_mode_lock_destructor); + SAFE_FREE(data.dptr); -/******************************************************************* - Static function that actually does the work for the generic function - below. -********************************************************************/ + return lck; +} -static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, - void *param) +BOOL get_delete_on_close_flag(SMB_DEV_T dev, SMB_INO_T inode, + const char *fname) { - 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 = NO_OPLOCK; + BOOL result; + struct share_mode_lock *lck = get_share_mode_lock(NULL, dev, inode, + fname); + result = lck->delete_on_close; + talloc_free(lck); + return result; } -/******************************************************************* - Remove an oplock port and mode entry from a share mode. -********************************************************************/ - -BOOL remove_share_oplock(files_struct *fsp) +BOOL is_valid_share_mode_entry(const struct share_mode_entry *e) { - share_mode_entry entry; - /* - * Fake up an entry for comparisons... - */ - fill_share_mode((char *)&entry, fsp, 0, 0); - return mod_share_mode(fsp->dev, fsp->inode, &entry, remove_share_oplock_fn, NULL); + int num_props = 0; + + num_props += ((e->op_type == NO_OPLOCK) ? 1 : 0); + num_props += (EXCLUSIVE_OPLOCK_TYPE(e->op_type) ? 1 : 0); + num_props += (LEVEL_II_OPLOCK_TYPE(e->op_type) ? 1 : 0); + + SMB_ASSERT(num_props <= 1); + return (num_props != 0); } -/******************************************************************* - Static function that actually does the work for the generic function - below. -********************************************************************/ +BOOL is_deferred_open_entry(const struct share_mode_entry *e) +{ + return (e->op_type == DEFERRED_OPEN_ENTRY); +} -static void downgrade_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode, - void *param) +BOOL is_unused_share_mode_entry(const struct share_mode_entry *e) { - DEBUG(10,("downgrade_share_oplock_fn: downgrading oplock info for entry dev=%x ino=%.0f\n", - (unsigned int)dev, (double)inode )); - entry->op_type = LEVEL_II_OPLOCK; + return (e->op_type == UNUSED_SHARE_MODE_ENTRY); } /******************************************************************* - Downgrade a oplock type from exclusive to level II. + Fill a share mode entry. ********************************************************************/ -BOOL downgrade_share_oplock(files_struct *fsp) +static void fill_share_mode_entry(struct share_mode_entry *e, + files_struct *fsp, + uint16 mid, uint16 op_type) { - share_mode_entry entry; - /* - * Fake up an entry for comparisons... - */ - fill_share_mode((char *)&entry, fsp, 0, 0); - return mod_share_mode(fsp->dev, fsp->inode, &entry, downgrade_share_oplock_fn, NULL); + ZERO_STRUCTP(e); + e->pid = procid_self(); + e->share_access = fsp->share_access; + e->private_options = fsp->fh->private_options; + e->access_mask = fsp->access_mask; + e->op_mid = mid; + e->op_type = op_type; + e->time.tv_sec = fsp->open_time.tv_sec; + e->time.tv_usec = fsp->open_time.tv_usec; + e->share_file_id = fsp->file_id; + e->dev = fsp->dev; + e->inode = fsp->inode; } -/******************************************************************* - Get/Set the delete on close flag in a set of share modes. - Return False on fail, True on success. -********************************************************************/ - -BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close) +static void fill_deferred_open_entry(struct share_mode_entry *e, + const struct timeval request_time, + SMB_DEV_T dev, SMB_INO_T ino, uint16 mid) { - TDB_DATA dbuf; - struct locking_data *data; - BOOL res; - TDB_DATA key = locking_key(dev, inode); + ZERO_STRUCTP(e); + e->pid = procid_self(); + e->op_mid = mid; + e->op_type = DEFERRED_OPEN_ENTRY; + e->time.tv_sec = request_time.tv_sec; + e->time.tv_usec = request_time.tv_usec; + e->dev = dev; + e->inode = ino; +} - /* read in the existing share modes */ - dbuf = tdb_fetch(tdb, key); - if (!dbuf.dptr) - return False; +static void add_share_mode_entry(struct share_mode_lock *lck, + const struct share_mode_entry *entry) +{ + int i; - data = (struct locking_data *)dbuf.dptr; + for (i=0; i<lck->num_share_modes; i++) { + struct share_mode_entry *e = &lck->share_modes[i]; + if (is_unused_share_mode_entry(e)) { + *e = *entry; + break; + } + } - /* Set/Unset the delete on close element. */ - data->u.s.delete_on_close = delete_on_close; + if (i == lck->num_share_modes) { + /* No unused entry found */ + ADD_TO_ARRAY(lck, struct share_mode_entry, *entry, + &lck->share_modes, &lck->num_share_modes); + } + lck->modified = True; +} - res = (tdb_store(tdb, key, dbuf, TDB_REPLACE)!=-1); +void set_share_mode(struct share_mode_lock *lck, files_struct *fsp, + uint16 mid, uint16 op_type) +{ + struct share_mode_entry entry; + fill_share_mode_entry(&entry, fsp, mid, op_type); + add_share_mode_entry(lck, &entry); +} - SAFE_FREE(dbuf.dptr); - return res; +void add_deferred_open(struct share_mode_lock *lck, uint16 mid, + struct timeval request_time, + SMB_DEV_T dev, SMB_INO_T ino) +{ + struct share_mode_entry entry; + fill_deferred_open_entry(&entry, request_time, dev, ino, mid); + add_share_mode_entry(lck, &entry); } /******************************************************************* - Print out a deferred open entry. + Check if two share mode entries are identical, ignoring oplock + and mid info and desired_access. ********************************************************************/ -char *deferred_open_str(int num, deferred_open_entry *e) +static BOOL share_modes_identical(struct share_mode_entry *e1, + struct share_mode_entry *e2) { - static pstring de_str; - - slprintf(de_str, sizeof(de_str)-1, "deferred_open_entry[%d]: \ -pid = %lu, mid = %u, dev = 0x%x, inode = %.0f, port = %u, time = [%u.%06u]", - num, (unsigned long)e->pid, (unsigned int)e->mid, (unsigned int)e->dev, (double)e->inode, - (unsigned int)e->port, - (unsigned int)e->time.tv_sec, (unsigned int)e->time.tv_usec ); +#if 1 /* JRA PARANOIA TEST - REMOVE LATER */ + if (procid_equal(&e1->pid, &e2->pid) && + e1->share_file_id == e2->share_file_id && + e1->dev == e2->dev && + e1->inode == e2->inode && + (e1->share_access) != (e2->share_access)) { + DEBUG(0,("PANIC: share_modes_identical: share_mode " + "mismatch (e1 = 0x%x, e2 = 0x%x). Logic error.\n", + (unsigned int)e1->share_access, + (unsigned int)e2->share_access )); + smb_panic("PANIC: share_modes_identical logic error.\n"); + } +#endif - return de_str; + return (procid_equal(&e1->pid, &e2->pid) && + (e1->share_access) == (e2->share_access) && + e1->dev == e2->dev && + e1->inode == e2->inode && + e1->share_file_id == e2->share_file_id ); } -/* Internal data structures for deferred opens... */ +static BOOL deferred_open_identical(struct share_mode_entry *e1, + struct share_mode_entry *e2) +{ + return (procid_equal(&e1->pid, &e2->pid) && + (e1->op_mid == e2->op_mid) && + (e1->dev == e2->dev) && + (e1->inode == e2->inode)); +} -struct de_locking_key { - char name[4]; - SMB_DEV_T dev; - SMB_INO_T inode; -}; +static struct share_mode_entry *find_share_mode_entry(struct share_mode_lock *lck, + struct share_mode_entry *entry) +{ + int i; -struct deferred_open_data { - union { - int num_deferred_open_entries; - deferred_open_entry dummy; /* Needed for alignment. */ - } u; - /* the following two entries are implicit - deferred_open_entry de_entries[num_deferred_open_entries]; - char file_name[]; - */ -}; + for (i=0; i<lck->num_share_modes; i++) { + struct share_mode_entry *e = &lck->share_modes[i]; + if (is_valid_share_mode_entry(entry) && + is_valid_share_mode_entry(e) && + share_modes_identical(e, entry)) { + return e; + } + if (is_deferred_open_entry(entry) && + is_deferred_open_entry(e) && + deferred_open_identical(e, entry)) { + return e; + } + } + return NULL; +} /******************************************************************* - Print out a deferred open table. + Del the share mode of a file for this process. Return the number of + entries left. ********************************************************************/ -static void print_deferred_open_table(struct deferred_open_data *data) +BOOL del_share_mode(struct share_mode_lock *lck, files_struct *fsp) { - int num_de_entries = data->u.num_deferred_open_entries; - deferred_open_entry *de_entries = (deferred_open_entry *)(data + 1); - int i; + struct share_mode_entry entry, *e; + + fill_share_mode_entry(&entry, fsp, 0, 0); - for (i = 0; i < num_de_entries; i++) { - deferred_open_entry *entry_p = &de_entries[i]; - DEBUG(10,("print_deferred_open_table: %s\n", deferred_open_str(i, entry_p) )); + e = find_share_mode_entry(lck, &entry); + if (e == NULL) { + return False; } + + e->op_type = UNUSED_SHARE_MODE_ENTRY; + lck->modified = True; + return True; } +void del_deferred_open_entry(struct share_mode_lock *lck, uint16 mid) +{ + struct share_mode_entry entry, *e; -/******************************************************************* - Form a static deferred open locking key for a dev/inode pair. -******************************************************************/ + fill_deferred_open_entry(&entry, timeval_zero(), + lck->dev, lck->ino, mid); -static TDB_DATA deferred_open_locking_key(SMB_DEV_T dev, SMB_INO_T inode) -{ - static struct de_locking_key key; - TDB_DATA kbuf; + e = find_share_mode_entry(lck, &entry); + if (e == NULL) { + return; + } - memset(&key, '\0', sizeof(key)); - memcpy(&key.name[0], "DOE", 4); - key.dev = dev; - key.inode = inode; - kbuf.dptr = (char *)&key; - kbuf.dsize = sizeof(key); - return kbuf; + e->op_type = UNUSED_SHARE_MODE_ENTRY; + lck->modified = True; } /******************************************************************* - Get all deferred open entries for a dev/inode pair. + Remove an oplock mid and mode entry from a share mode. ********************************************************************/ -int get_deferred_opens(connection_struct *conn, - SMB_DEV_T dev, SMB_INO_T inode, - deferred_open_entry **pp_de_entries) +BOOL remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp) { - TDB_DATA dbuf; - struct deferred_open_data *data; - int num_de_entries; - deferred_open_entry *de_entries = NULL; - TDB_DATA key = deferred_open_locking_key(dev, inode); + struct share_mode_entry entry, *e; - *pp_de_entries = NULL; + fill_share_mode_entry(&entry, fsp, 0, 0); - dbuf = tdb_fetch(deferred_open_tdb, key); - if (!dbuf.dptr) - return 0; - - data = (struct deferred_open_data *)dbuf.dptr; - num_de_entries = data->u.num_deferred_open_entries; - if(num_de_entries) { - pstring fname; - int i; - int del_count = 0; - - de_entries = (deferred_open_entry *)memdup(dbuf.dptr + sizeof(*data), - num_de_entries * sizeof(deferred_open_entry)); - - if (!de_entries) { - SAFE_FREE(dbuf.dptr); - return 0; - } + e = find_share_mode_entry(lck, &entry); + if (e == NULL) { + return False; + } - /* Save off the associated filename. */ - pstrcpy(fname, dbuf.dptr + sizeof(*data) + num_de_entries * sizeof(deferred_open_entry)); + e->op_mid = 0; + e->op_type = NO_OPLOCK; + lck->modified = True; + return True; +} - /* - * Ensure that each entry has a real process attached. - */ +/******************************************************************* + Downgrade a oplock type from exclusive to level II. +********************************************************************/ - for (i = 0; i < num_de_entries; ) { - deferred_open_entry *entry_p = &de_entries[i]; - if (process_exists(entry_p->pid)) { - DEBUG(10,("get_deferred_opens: %s\n", deferred_open_str(i, entry_p) )); - i++; - } else { - DEBUG(10,("get_deferred_opens: deleted %s\n", deferred_open_str(i, entry_p) )); - if (num_de_entries - i - 1 > 0) { - memcpy( &de_entries[i], &de_entries[i+1], - sizeof(deferred_open_entry) * (num_de_entries - i - 1)); - } - num_de_entries--; - del_count++; - } - } +BOOL downgrade_share_oplock(struct share_mode_lock *lck, files_struct *fsp) +{ + struct share_mode_entry entry, *e; - /* Did we delete any ? If so, re-store in tdb. */ - if (del_count) { - data->u.num_deferred_open_entries = num_de_entries; - - if (num_de_entries) { - memcpy(dbuf.dptr + sizeof(*data), de_entries, - num_de_entries * sizeof(deferred_open_entry)); - /* Append the filename. */ - pstrcpy(dbuf.dptr + sizeof(*data) + num_de_entries * sizeof(deferred_open_entry), fname); - } + fill_share_mode_entry(&entry, fsp, 0, 0); - /* The record has shrunk a bit */ - dbuf.dsize -= del_count * sizeof(deferred_open_entry); - - if (data->u.num_deferred_open_entries == 0) { - if (tdb_delete(deferred_open_tdb, key) == -1) { - SAFE_FREE(de_entries); - SAFE_FREE(dbuf.dptr); - return 0; - } - } else { - if (tdb_store(deferred_open_tdb, key, dbuf, TDB_REPLACE) == -1) { - SAFE_FREE(de_entries); - SAFE_FREE(dbuf.dptr); - return 0; - } - } - } + e = find_share_mode_entry(lck, &entry); + if (e == NULL) { + return False; } - SAFE_FREE(dbuf.dptr); - *pp_de_entries = de_entries; - return num_de_entries; + e->op_type = LEVEL_II_OPLOCK; + lck->modified = True; + return True; } + /******************************************************************* - Check if two deferred open entries are identical. + We've just told all the smbd's that our level2 or fake level2 has been + written to. ********************************************************************/ - -static BOOL deferred_open_entries_identical( deferred_open_entry *e1, deferred_open_entry *e2) +BOOL remove_all_share_oplocks(struct share_mode_lock *lck, files_struct *fsp) { - return (e1->pid == e2->pid && - e1->mid == e2->mid && - e1->port == e2->port && - e1->dev == e2->dev && - e1->inode == e2->inode && - e1->time.tv_sec == e2->time.tv_sec && - e1->time.tv_usec == e2->time.tv_usec); + int i; + for (i=0; i<lck->num_share_modes; i++) { + struct share_mode_entry *e = &lck->share_modes[i]; + if (!is_valid_share_mode_entry(e)) { + continue; + } + if (e->op_type == NO_OPLOCK) { + continue; + } + e->op_type = NO_OPLOCK; + lck->modified = True; + } + return True; } -/******************************************************************* - Delete a specific deferred open entry. - Ignore if no entry deleted. -********************************************************************/ +/**************************************************************************** + Deal with the internal needs of setting the delete on close flag. Note that + as the tdb locking is recursive, it is safe to call this from within + open_file_shared. JRA. +****************************************************************************/ -BOOL delete_deferred_open_entry(deferred_open_entry *entry) +NTSTATUS can_set_delete_on_close(files_struct *fsp, BOOL delete_on_close, + uint32 dosmode) { - TDB_DATA dbuf; - struct deferred_open_data *data; - int i, del_count=0; - deferred_open_entry *de_entries; - BOOL ret = True; - TDB_DATA key = deferred_open_locking_key(entry->dev, entry->inode); - - /* read in the existing share modes */ - dbuf = tdb_fetch(deferred_open_tdb, key); - if (!dbuf.dptr) - return -1; - - data = (struct deferred_open_data *)dbuf.dptr; - de_entries = (deferred_open_entry *)(dbuf.dptr + sizeof(*data)); + if (!delete_on_close) { + return NT_STATUS_OK; + } /* - * Find any with this pid and delete it - * by overwriting with the rest of the data - * from the record. + * Only allow delete on close for writable files. */ - DEBUG(10,("delete_deferred_open_entry: num_deferred_open_entries = %d\n", - data->u.num_deferred_open_entries )); - - for (i=0;i<data->u.num_deferred_open_entries;) { - if (deferred_open_entries_identical(&de_entries[i], entry)) { - DEBUG(10,("delete_deferred_open_entry: deleted %s\n", - deferred_open_str(i, &de_entries[i]) )); - - data->u.num_deferred_open_entries--; - if ((dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*de_entries))) > 0) { - memmove(&de_entries[i], &de_entries[i+1], - dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*de_entries))); - } - del_count++; - - DEBUG(10,("delete_deferred_open_entry: deleting entry %d\n", i )); - - } else { - i++; - } + if ((dosmode & aRONLY) && + !lp_delete_readonly(SNUM(fsp->conn))) { + DEBUG(10,("can_set_delete_on_close: file %s delete on close " + "flag set but file attribute is readonly.\n", + fsp->fsp_name )); + return NT_STATUS_CANNOT_DELETE; } - SMB_ASSERT(del_count == 0 || del_count == 1); - - if (del_count) { - /* the record may have shrunk a bit */ - dbuf.dsize -= del_count * sizeof(*de_entries); + /* + * Only allow delete on close for writable shares. + */ - /* store it back in the database */ - if (data->u.num_deferred_open_entries == 0) { - if (tdb_delete(deferred_open_tdb, key) == -1) - ret = False; - } else { - if (tdb_store(deferred_open_tdb, key, dbuf, TDB_REPLACE) == -1) - ret = False; - } + if (!CAN_WRITE(fsp->conn)) { + DEBUG(10,("can_set_delete_on_close: file %s delete on " + "close flag set but write access denied on share.\n", + fsp->fsp_name )); + return NT_STATUS_ACCESS_DENIED; } - DEBUG(10,("delete_deferred_open_entry: Remaining table.\n")); - print_deferred_open_table((struct deferred_open_data*)dbuf.dptr); - SAFE_FREE(dbuf.dptr); - return ret; -} -/******************************************************************* - Fill a deferred open entry. -********************************************************************/ + /* + * Only allow delete on close for files/directories opened with delete + * intent. + */ -static void fill_deferred_open(char *p, uint16 mid, struct timeval *ptv, SMB_DEV_T dev, SMB_INO_T inode, uint16 port) -{ - deferred_open_entry *e = (deferred_open_entry *)p; - void *x = &e->time; /* Needed to force alignment. p may not be aligned.... */ + if (!(fsp->access_mask & DELETE_ACCESS)) { + DEBUG(10,("can_set_delete_on_close: file %s delete on " + "close flag set but delete access denied.\n", + fsp->fsp_name )); + return NT_STATUS_ACCESS_DENIED; + } - memset(e, '\0', sizeof(deferred_open_entry)); - e->mid = mid; - e->pid = sys_getpid(); - memcpy(x, ptv, sizeof(struct timeval)); - e->dev = dev; - e->inode = inode; - e->port = port; + return NT_STATUS_OK; } -/******************************************************************* - Add a deferred open record. Return False on fail, True on success. -********************************************************************/ +/**************************************************************************** + Sets the delete on close flag over all share modes on this file. + 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. +****************************************************************************/ -BOOL add_deferred_open(uint16 mid, struct timeval *ptv, SMB_DEV_T dev, SMB_INO_T inode, uint16 port, const char *fname) +BOOL set_delete_on_close(files_struct *fsp, BOOL delete_on_close) { - TDB_DATA dbuf; - struct deferred_open_data *data; - char *p=NULL; - int size; - TDB_DATA key = deferred_open_locking_key(dev, inode); - BOOL ret = True; - - /* read in the existing deferred open records if any */ - dbuf = tdb_fetch(deferred_open_tdb, key); - if (!dbuf.dptr) { - size_t offset; - /* we'll need to create a new record */ - - size = sizeof(*data) + sizeof(deferred_open_entry) + strlen(fname) + 1; - p = (char *)SMB_MALLOC(size); - if (!p) - return False; - data = (struct deferred_open_data *)p; - ZERO_STRUCT(data->u.dummy); /* Keep valgrind happy */ - data->u.num_deferred_open_entries = 1; + struct share_mode_lock *lck; - DEBUG(10,("add_deferred_open: creating entry for file %s. num_deferred_open_entries = 1\n", - fname )); - - offset = sizeof(*data) + sizeof(deferred_open_entry); - safe_strcpy(p + offset, fname, size - offset - 1); - fill_deferred_open(p + sizeof(*data), mid, ptv, dev, inode, port); - dbuf.dptr = p; - dbuf.dsize = size; - if (tdb_store(deferred_open_tdb, key, dbuf, TDB_REPLACE) == -1) - ret = False; - - print_deferred_open_table((struct deferred_open_data *)p); - - SAFE_FREE(p); - return ret; - } - - /* we're adding to an existing entry - this is a bit fiddly */ - data = (struct deferred_open_data *)dbuf.dptr; + DEBUG(10,("set_delete_on_close: %s delete on close flag for " + "fnum = %d, file %s\n", + delete_on_close ? "Adding" : "Removing", fsp->fnum, + fsp->fsp_name )); - data->u.num_deferred_open_entries++; - - DEBUG(10,("add_deferred_open: adding entry for file %s. new num_deferred_open_entries = %d\n", - fname, data->u.num_deferred_open_entries )); + if (fsp->is_directory || fsp->is_stat) + return True; - size = dbuf.dsize + sizeof(deferred_open_entry); - p = SMB_MALLOC(size); - if (!p) { - SAFE_FREE(dbuf.dptr); + lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL); + if (lck == NULL) { return False; } - memcpy(p, dbuf.dptr, sizeof(*data)); - fill_deferred_open(p + sizeof(*data), mid, ptv, dev, inode, port); - memcpy(p + sizeof(*data) + sizeof(deferred_open_entry), dbuf.dptr + sizeof(*data), - dbuf.dsize - sizeof(*data)); - SAFE_FREE(dbuf.dptr); - dbuf.dptr = p; - dbuf.dsize = size; - if (tdb_store(deferred_open_tdb, key, dbuf, TDB_REPLACE) == -1) - ret = False; - print_deferred_open_table((struct deferred_open_data *)p); - SAFE_FREE(p); - return ret; -} + if (lck->delete_on_close != delete_on_close) { + lck->delete_on_close = delete_on_close; + lck->modified = True; + } -/**************************************************************************** - Traverse the whole database with this function, calling traverse_callback - on each share mode -****************************************************************************/ + talloc_free(lck); + return True; +} static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, - void* state) + void *state) { struct locking_data *data; - share_mode_entry *shares; + struct share_mode_entry *shares; char *name; int i; - - SHAREMODE_FN(traverse_callback) = (SHAREMODE_FN_CAST())state; + void (*traverse_callback)(struct share_mode_entry *, char *) = state; /* Ensure this is a locking_key record. */ if (kbuf.dsize != sizeof(struct locking_key)) return 0; data = (struct locking_data *)dbuf.dptr; - shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data)); - name = dbuf.dptr + sizeof(*data) + data->u.s.num_share_mode_entries*sizeof(*shares); + shares = (struct share_mode_entry *)(dbuf.dptr + sizeof(*data)); + name = dbuf.dptr + sizeof(*data) + + data->u.s.num_share_mode_entries*sizeof(*shares); for (i=0;i<data->u.s.num_share_mode_entries;i++) { traverse_callback(&shares[i], name); @@ -1299,9 +1005,9 @@ static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, share mode system. ********************************************************************/ -int share_mode_forall(SHAREMODE_FN(fn)) +int share_mode_forall(void (*fn)(const struct share_mode_entry *, char *)) { - if (!tdb) + if (tdb == NULL) return 0; - return tdb_traverse(tdb, traverse_fn, (void*)fn); + return tdb_traverse(tdb, traverse_fn, fn); } |