BOOL modify_delete_flag( SMB_DEV_T dev, SMB_INO_T inode, BOOL delete_on_close) { TDB_DATA dbuf; struct locking_data *data; int i; share_mode_entry *shares; /* 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)); /* Set/Unset the delete on close element. */ for (i=0;i<data->u.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) ); } /* store it back */ if (data->u.num_share_mode_entries) { if (tdb_store(tdb, locking_key(dev,inode), dbuf, TDB_REPLACE)==-1) { SAFE_FREE(dbuf.dptr); return False; } } SAFE_FREE(dbuf.dptr); return True; }
/******************************************************************* Get all share mode entries for a dev/inode pair. ********************************************************************/ int get_share_modes(struct vfs_connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry ** shares) { TDB_DATA dbuf; struct locking_data *data; int ret; *shares = NULL; dbuf = tdb_fetch(tdb, locking_key(dev, inode)); if (!dbuf.dptr) return 0; data = (struct locking_data *)dbuf.dptr; ret = data->num_share_mode_entries; if (ret) *shares = (share_mode_entry *) memdup(dbuf.dptr + sizeof(*data), ret * sizeof(**shares)); free(dbuf.dptr); if (!*shares) return 0; return ret; }
static int share_mode_lock_destructor(void *p) { 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; if (!lck->modified) { goto done; } data = unparse_share_modes(lck); 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; } if (tdb_store(tdb, key, data, TDB_REPLACE) == -1) { smb_panic("Could not store share mode entry\n"); } done: tdb_chainunlock(tdb, key); return 0; }
struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx, struct file_id id) { struct share_mode_lock *lck; TDB_DATA key = locking_key(&id); TDB_DATA data; NTSTATUS status; status = dbwrap_fetch(lock_db, talloc_tos(), key, &data); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("Could not fetch share entry\n")); return NULL; } if (data.dptr == NULL) { return NULL; } lck = talloc(mem_ctx, struct share_mode_lock); if (lck == NULL) { TALLOC_FREE(data.dptr); return NULL; } lck->data = parse_share_modes(lck, data); TALLOC_FREE(data.dptr); if (lck->data == NULL) { TALLOC_FREE(lck); return NULL; } return lck; }
BOOL get_delete_on_close_flag(SMB_DEV_T dev, SMB_INO_T inode) { TDB_DATA key = locking_key(dev, inode); BOOL result = False; tdb_parse_record(tdb, key, pull_delete_on_close_flag, (void *)&result); return result; }
BOOL brl_locktest(SMB_DEV_T dev, SMB_INO_T ino, int fnum, uint16 smbpid, pid_t pid, uint16 tid, br_off start, br_off size, enum brl_type lock_type, int check_self) { TDB_DATA kbuf, dbuf; int count, i; struct lock_struct lock, *locks; kbuf = locking_key(dev,ino); dbuf.dptr = NULL; tdb_chainlock(tdb, kbuf); dbuf = tdb_fetch(tdb, kbuf); lock.context.smbpid = smbpid; lock.context.pid = pid; lock.context.tid = tid; lock.start = start; lock.size = size; lock.fnum = fnum; lock.lock_type = lock_type; if (dbuf.dptr) { /* there are existing locks - make sure they don't conflict */ locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { if (check_self) { if (brl_conflict(&locks[i], &lock)) goto fail; } else { /* * Our own locks don't conflict. */ if (brl_conflict_other(&locks[i], &lock)) goto fail; } } } /* no conflicts - we could have added it */ SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return True; fail: SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return False; }
static struct share_mode_lock *get_share_mode_lock_internal( TALLOC_CTX *mem_ctx, struct file_id id, const char *servicepath, const struct smb_filename *smb_fname, const struct timespec *old_write_time) { struct share_mode_lock *lck; struct share_mode_data *d; struct db_record *rec; TDB_DATA key = locking_key(&id); TDB_DATA value; rec = dbwrap_fetch_locked(lock_db, mem_ctx, key); if (rec == NULL) { DEBUG(3, ("Could not lock share entry\n")); return NULL; } value = dbwrap_record_get_value(rec); if (value.dptr == NULL) { d = fresh_share_mode_lock(mem_ctx, servicepath, smb_fname, old_write_time); } else { d = parse_share_modes(mem_ctx, value); } if (d == NULL) { DEBUG(5, ("get_share_mode_lock_internal: " "Could not get share mode lock\n")); TALLOC_FREE(rec); return NULL; } d->id = id; d->record = talloc_move(d, &rec); talloc_set_destructor(d, share_mode_data_destructor); lck = talloc(mem_ctx, struct share_mode_lock); if (lck == NULL) { DEBUG(1, ("talloc failed\n")); TALLOC_FREE(d); return NULL; } lck->data = talloc_move(lck, &d); return lck; }
struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx, struct file_id id) { struct share_mode_lock *lck; TDB_DATA key = locking_key(&id); NTSTATUS status; lck = talloc(mem_ctx, struct share_mode_lock); if (lck == NULL) { DEBUG(0, ("talloc failed\n")); return NULL; } status = dbwrap_parse_record( lock_db, key, fetch_share_mode_unlocked_parser, lck); if (!NT_STATUS_IS_OK(status) || (lck->data == NULL)) { TALLOC_FREE(lck); return NULL; } return lck; }
struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, SMB_DEV_T dev, SMB_INO_T ino, const char *servicepath, const char *fname) { struct share_mode_lock *lck; TDB_DATA key = locking_key(dev, ino); TDB_DATA data; lck = TALLOC_P(mem_ctx, struct share_mode_lock); if (lck == NULL) { DEBUG(0, ("talloc failed\n")); return NULL; } /* Ensure we set every field here as the destructor must be valid even if parse_share_modes fails. */ lck->servicepath = NULL; lck->filename = NULL; lck->dev = dev; lck->ino = ino; lck->num_share_modes = 0; lck->share_modes = NULL; lck->delete_token = NULL; lck->delete_on_close = False; lck->initial_delete_on_close = False; lck->fresh = False; lck->modified = False; if (tdb_chainlock(tdb, key) != 0) { DEBUG(3, ("Could not lock share entry\n")); TALLOC_FREE(lck); return NULL; } /* We must set the destructor immediately after the chainlock ensure the lock is cleaned up on any of the error return paths below. */ talloc_set_destructor(lck, share_mode_lock_destructor); data = tdb_fetch(tdb, key); lck->fresh = (data.dptr == NULL); if (lck->fresh) { if (fname == NULL || servicepath == NULL) { TALLOC_FREE(lck); return NULL; } lck->filename = talloc_strdup(lck, fname); lck->servicepath = talloc_strdup(lck, servicepath); if (lck->filename == NULL || lck->servicepath == 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(data.dptr); return lck; }
BOOL lock_share_entry(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode) { return tdb_chainlock(tdb, locking_key(dev, inode)) == 0; }
void brl_close(SMB_DEV_T dev, SMB_INO_T ino, pid_t pid, int tid, int fnum) { TDB_DATA kbuf, dbuf; int count, i, j, dcount=0; struct lock_struct *locks; kbuf = locking_key(dev,ino); dbuf.dptr = NULL; tdb_chainlock(tdb, kbuf); dbuf = tdb_fetch(tdb, kbuf); if (!dbuf.dptr) goto fail; /* there are existing locks - remove any for this fnum */ locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { struct lock_struct *lock = &locks[i]; if (lock->context.tid == tid && lock->context.pid == pid && lock->fnum == fnum) { /* Send unlock messages to any pending waiters that overlap. */ for (j=0; j<count; j++) { struct lock_struct *pend_lock = &locks[j]; /* Ignore our own or non-pending locks. */ if (pend_lock->lock_type != PENDING_LOCK) continue; if (pend_lock->context.tid == tid && pend_lock->context.pid == pid && pend_lock->fnum == fnum) continue; /* We could send specific lock info here... */ if (brl_pending_overlap(lock, pend_lock)) message_send_pid(pend_lock->context.pid, MSG_SMB_UNLOCK, NULL, 0, True); } /* found it - delete it */ if (count > 1 && i < count-1) { memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i)); } count--; i--; dcount++; } } if (count == 0) { tdb_delete(tdb, kbuf); } else if (count < (dbuf.dsize / sizeof(*locks))) { dbuf.dsize -= dcount * sizeof(*locks); tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); } /* we didn't find it */ fail: SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); }
BOOL brl_unlock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, uint16 smbpid, pid_t pid, uint16 tid, br_off start, br_off size, BOOL remove_pending_locks_only) { TDB_DATA kbuf, dbuf; int count, i, j; struct lock_struct *locks; struct lock_context context; kbuf = locking_key(dev,ino); dbuf.dptr = NULL; tdb_chainlock(tdb, kbuf); dbuf = tdb_fetch(tdb, kbuf); if (!dbuf.dptr) { DEBUG(10,("brl_unlock: tdb_fetch failed !\n")); goto fail; } context.smbpid = smbpid; context.pid = pid; context.tid = tid; /* there are existing locks - find a match */ locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); #if ZERO_ZERO for (i=0; i<count; i++) { struct lock_struct *lock = &locks[i]; if (lock->lock_type == WRITE_LOCK && brl_same_context(&lock->context, &context) && lock->fnum == fnum && lock->start == start && lock->size == size) { /* found it - delete it */ if (count == 1) { tdb_delete(tdb, kbuf); } else { if (i < count-1) { memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i)); } dbuf.dsize -= sizeof(*locks); tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); } SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return True; } } #endif locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { struct lock_struct *lock = &locks[i]; if (brl_same_context(&lock->context, &context) && lock->fnum == fnum && lock->start == start && lock->size == size) { if (remove_pending_locks_only && lock->lock_type != PENDING_LOCK) continue; if (lock->lock_type != PENDING_LOCK) { /* Send unlock messages to any pending waiters that overlap. */ for (j=0; j<count; j++) { struct lock_struct *pend_lock = &locks[j]; /* Ignore non-pending locks. */ if (pend_lock->lock_type != PENDING_LOCK) continue; /* 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 )); message_send_pid(pend_lock->context.pid, MSG_SMB_UNLOCK, NULL, 0, True); } } } /* found it - delete it */ if (count == 1) { tdb_delete(tdb, kbuf); } else { if (i < count-1) { memmove(&locks[i], &locks[i+1], sizeof(*locks)*((count-1) - i)); } dbuf.dsize -= sizeof(*locks); tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); } SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return True; } } /* we didn't find it */ fail: SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return False; }
NTSTATUS brl_lock(SMB_DEV_T dev, SMB_INO_T ino, int fnum, uint16 smbpid, pid_t pid, uint16 tid, br_off start, br_off size, enum brl_type lock_type) { TDB_DATA kbuf, dbuf; int count, i; struct lock_struct lock, *locks; char *tp; NTSTATUS status = NT_STATUS_OK; static int last_failed = -1; static br_off last_failed_start; kbuf = locking_key(dev,ino); dbuf.dptr = NULL; #if !ZERO_ZERO if (start == 0 && size == 0) { DEBUG(0,("client sent 0/0 lock - please report this\n")); } #endif tdb_chainlock(tdb, kbuf); dbuf = tdb_fetch(tdb, kbuf); lock.context.smbpid = smbpid; lock.context.pid = pid; lock.context.tid = tid; lock.start = start; lock.size = size; lock.fnum = fnum; lock.lock_type = lock_type; if (dbuf.dptr) { /* there are existing locks - make sure they don't conflict */ locks = (struct lock_struct *)dbuf.dptr; count = dbuf.dsize / sizeof(*locks); for (i=0; i<count; i++) { if (brl_conflict(&locks[i], &lock)) { status = NT_STATUS_LOCK_NOT_GRANTED; goto fail; } #if ZERO_ZERO if (lock.start == 0 && lock.size == 0 && locks[i].size == 0) { break; } #endif } } /* no conflicts - add it to the list of locks */ tp = Realloc(dbuf.dptr, dbuf.dsize + sizeof(*locks)); if (!tp) { status = NT_STATUS_NO_MEMORY; goto fail; } else { dbuf.dptr = tp; } memcpy(dbuf.dptr + dbuf.dsize, &lock, sizeof(lock)); dbuf.dsize += sizeof(lock); #if ZERO_ZERO /* sort the lock list */ qsort(dbuf.dptr, dbuf.dsize/sizeof(lock), sizeof(lock), lock_compare); #endif tdb_store(tdb, kbuf, dbuf, TDB_REPLACE); SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return NT_STATUS_OK; fail: /* this is a nasty hack to try to simulate the lock result cache code in w2k. It isn't completely accurate as I haven't yet worked out the correct semantics (tridge) */ if (last_failed == fnum && last_failed_start == start && NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) { status = NT_STATUS_FILE_LOCK_CONFLICT; } last_failed = fnum; last_failed_start = start; SAFE_FREE(dbuf.dptr); tdb_chainunlock(tdb, kbuf); return status; }
int get_share_modes(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry **pp_shares) { TDB_DATA dbuf; struct locking_data *data; int num_share_modes; share_mode_entry *shares = NULL; *pp_shares = NULL; dbuf = tdb_fetch(tdb, locking_key(dev, inode)); if (!dbuf.dptr) return 0; data = (struct locking_data *)dbuf.dptr; num_share_modes = data->u.num_share_mode_entries; if(num_share_modes) { 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; } /* * Ensure that each entry has a real process attached. */ 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) )); memcpy( &shares[i], &shares[i+1], sizeof(share_mode_entry) * (num_share_modes - i - 1)); num_share_modes--; del_count++; } } /* Did we delete any ? If so, re-store in tdb. */ if (del_count) { data->u.num_share_mode_entries = num_share_modes; if (num_share_modes) memcpy(dbuf.dptr + sizeof(*data), shares, num_share_modes * sizeof(share_mode_entry)); /* The record has shrunk a bit */ dbuf.dsize -= del_count * sizeof(share_mode_entry); if (tdb_store(tdb, locking_key(dev, inode), dbuf, TDB_REPLACE) == -1) { SAFE_FREE(shares); SAFE_FREE(dbuf.dptr); return 0; } } } SAFE_FREE(dbuf.dptr); *pp_shares = shares; return num_share_modes; }
/******************************************************************* Unlock a hash bucket entry. ******************************************************************/ BOOL unlock_share_entry_fsp(files_struct * fsp) { return tdb_unlockchain(tdb, locking_key(fsp->sbuf.st_dev, fsp->sbuf.st_ino)) == 0; }
static TDB_DATA locking_key_fsp(files_struct *fsp) { return locking_key(fsp->dev, fsp->inode); }
static TDB_DATA locking_key_fsp(files_struct * fsp) { return locking_key(fsp->sbuf.st_dev, fsp->sbuf.st_ino); }
BOOL lock_share_entry_fsp(files_struct *fsp) { return tdb_chainlock(tdb, locking_key(fsp->dev, fsp->inode)) == 0; }
ssize_t del_share_entry( SMB_DEV_T dev, SMB_INO_T inode, share_mode_entry *entry, share_mode_entry **ppse) { TDB_DATA dbuf; struct locking_data *data; int i, del_count=0; share_mode_entry *shares; ssize_t count = 0; if (ppse) *ppse = NULL; /* read in the existing share modes */ dbuf = tdb_fetch(tdb, locking_key(dev, inode)); if (!dbuf.dptr) return -1; data = (struct locking_data *)dbuf.dptr; 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.num_share_mode_entries )); for (i=0;i<data->u.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.num_share_mode_entries--; memmove(&shares[i], &shares[i+1], dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares))); del_count++; DEBUG(10,("del_share_entry: deleting entry %d\n", i )); } else { i++; } } if (del_count) { /* the record may have shrunk a bit */ dbuf.dsize -= del_count * sizeof(*shares); count = (ssize_t)data->u.num_share_mode_entries; /* store it back in the database */ if (data->u.num_share_mode_entries == 0) { if (tdb_delete(tdb, locking_key(dev, inode)) == -1) count = -1; } else { if (tdb_store(tdb, locking_key(dev, inode), dbuf, TDB_REPLACE) == -1) count = -1; } } DEBUG(10,("del_share_entry: Remaining table.\n")); print_share_mode_table((struct locking_data *)dbuf.dptr); SAFE_FREE(dbuf.dptr); return count; }
void unlock_share_entry(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode) { tdb_chainunlock(tdb, locking_key(dev, inode)); }
/******************************************************************* Unlock a hash bucket entry. ******************************************************************/ BOOL unlock_share_entry(struct vfs_connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode) { return tdb_unlockchain(tdb, locking_key(dev, inode)) == 0; }
void unlock_share_entry_fsp(files_struct *fsp) { tdb_chainunlock(tdb, locking_key(fsp->dev, fsp->inode)); }