📄 locking.c
字号:
if (num_valid == 0) { return result; } sp_len = strlen(lck->servicepath); result.dsize = sizeof(*data) + lck->num_share_modes * sizeof(struct share_mode_entry) + sp_len + 1 + strlen(lck->filename) + 1; result.dptr = talloc_size(lck, result.dsize); if (result.dptr == NULL) { smb_panic("talloc failed\n"); } 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->servicepath, result.dsize - offset - 1); offset += sp_len + 1; safe_strcpy(result.dptr + offset, lck->filename, result.dsize - offset - 1); if (DEBUGLEVEL >= 10) { print_share_mode_table(data); } return result;}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 *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_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 get_delete_on_close_flag(SMB_DEV_T dev, SMB_INO_T inode, const char *fname){ BOOL result; struct share_mode_lock *lck = get_share_mode_lock(NULL, dev, inode, NULL, NULL); if (!lck) { return False; } result = lck->delete_on_close; talloc_free(lck); return result;}BOOL is_valid_share_mode_entry(const struct share_mode_entry *e){ 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);}BOOL is_deferred_open_entry(const struct share_mode_entry *e){ return (e->op_type == DEFERRED_OPEN_ENTRY);}BOOL is_unused_share_mode_entry(const struct share_mode_entry *e){ return (e->op_type == UNUSED_SHARE_MODE_ENTRY);}/******************************************************************* Fill a share mode entry.********************************************************************/static void fill_share_mode_entry(struct share_mode_entry *e, files_struct *fsp, uint16 mid, uint16 op_type){ 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;}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){ 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;}static void add_share_mode_entry(struct share_mode_lock *lck, const struct share_mode_entry *entry){ int i; 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; } } 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;}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);}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);}/******************************************************************* Check if two share mode entries are identical, ignoring oplock and mid info and desired_access.********************************************************************/static BOOL share_modes_identical(struct share_mode_entry *e1, struct share_mode_entry *e2){#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 (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 );}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));}static struct share_mode_entry *find_share_mode_entry(struct share_mode_lock *lck, struct share_mode_entry *entry){ 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(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;}/******************************************************************* Del the share mode of a file for this process. Return the number of entries left.********************************************************************/BOOL del_share_mode(struct share_mode_lock *lck, files_struct *fsp){ struct share_mode_entry entry, *e; fill_share_mode_entry(&entry, fsp, 0, 0); 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; fill_deferred_open_entry(&entry, timeval_zero(), lck->dev, lck->ino, mid); e = find_share_mode_entry(lck, &entry); if (e == NULL) { return; } e->op_type = UNUSED_SHARE_MODE_ENTRY; lck->modified = True;}/******************************************************************* Remove an oplock mid and mode entry from a share mode.********************************************************************/BOOL remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp){ struct share_mode_entry entry, *e; fill_share_mode_entry(&entry, fsp, 0, 0); e = find_share_mode_entry(lck, &entry); if (e == NULL) { return False; } e->op_mid = 0; e->op_type = NO_OPLOCK; lck->modified = True; return True;}/******************************************************************* Downgrade a oplock type from exclusive to level II.********************************************************************/BOOL downgrade_share_oplock(struct share_mode_lock *lck, files_struct *fsp){ struct share_mode_entry entry, *e; fill_share_mode_entry(&entry, fsp, 0, 0); e = find_share_mode_entry(lck, &entry); if (e == NULL) { return False; } e->op_type = LEVEL_II_OPLOCK; lck->modified = True; return True;}/**************************************************************************** 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.****************************************************************************/NTSTATUS can_set_delete_on_close(files_struct *fsp, BOOL delete_on_close, uint32 dosmode){ if (!delete_on_close) { return NT_STATUS_OK; } /* * Only allow delete on close for writable files. */ 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; } /* * Only allow delete on close for writable shares. */ 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; } /* * Only allow delete on close for files/directories opened with delete * intent. */ 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; } return NT_STATUS_OK;}/**************************************************************************** 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 set_delete_on_close(files_struct *fsp, BOOL delete_on_close){ struct share_mode_lock *lck; 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 )); if (fsp->is_stat) { return True; } lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL); if (lck == NULL) { return False; } if (lck->delete_on_close != delete_on_close) { lck->delete_on_close = delete_on_close; lck->modified = True; } talloc_free(lck); return True;}static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state){ struct locking_data *data; struct share_mode_entry *shares; const char *sharepath; const char *fname; int i; void (*traverse_callback)(struct share_mode_entry *, const char *, const 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 = (struct share_mode_entry *)(dbuf.dptr + sizeof(*data)); sharepath = dbuf.dptr + sizeof(*data) + data->u.s.num_share_mode_entries*sizeof(*shares); fname = dbuf.dptr + sizeof(*data) + data->u.s.num_share_mode_entries*sizeof(*shares) + strlen(sharepath) + 1; for (i=0;i<data->u.s.num_share_mode_entries;i++) { traverse_callback(&shares[i], sharepath, fname); } return 0;}/******************************************************************* Call the specified function on each entry under management by the share mode system.********************************************************************/int share_mode_forall(void (*fn)(const struct share_mode_entry *, const char *, const char *)){ if (tdb == NULL) return 0; return tdb_traverse(tdb, traverse_fn, fn);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -