The Samba-Bugzilla – Attachment 3393 Details for
Bug 5512
Panic with 3.2.0rc1 on Solaris10/ADDomainMember
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
locking.c with the patch applied
locking.c (text/plain), 39.52 KB, created by
Volker Lendecke
on 2008-07-07 07:28:48 UTC
(
hide
)
Description:
locking.c with the patch applied
Filename:
MIME Type:
Creator:
Volker Lendecke
Created:
2008-07-07 07:28:48 UTC
Size:
39.52 KB
patch
obsolete
>/* > Unix SMB/CIFS implementation. > Locking functions > Copyright (C) Andrew Tridgell 1992-2000 > Copyright (C) Jeremy Allison 1992-2006 > Copyright (C) Volker Lendecke 2005 > > This program is free software; you can redistribute it and/or modify > it under the terms of the GNU General Public License as published by > the Free Software Foundation; either version 3 of the License, or > (at your option) any later version. > > This program is distributed in the hope that it will be useful, > but WITHOUT ANY WARRANTY; without even the implied warranty of > MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > GNU General Public License for more details. > > You should have received a copy of the GNU General Public License > along with this program. If not, see <http://www.gnu.org/licenses/>. > > Revision History: > > 12 aug 96: Erik.Devriendt@te6.siemens.be > added support for shared memory implementation of share mode locking > > May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode > locking to deal with multiple share modes per open file. > > September 1997. Jeremy Allison (jallison@whistle.com). Added oplock > support. > > rewrtten completely to use new tdb code. Tridge, Dec '99 > > Added POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000. > Added Unix Extensions POSIX locking support. Jeremy Allison Mar 2006. >*/ > >#include "includes.h" > >#undef DBGC_CLASS >#define DBGC_CLASS DBGC_LOCKING > >#define NO_LOCKING_COUNT (-1) > >/* the locking database handle */ >static struct db_context *lock_db; > >/**************************************************************************** > Debugging aids :-). >****************************************************************************/ > >const char *lock_type_name(enum brl_type lock_type) >{ > switch (lock_type) { > case READ_LOCK: > return "READ"; > case WRITE_LOCK: > return "WRITE"; > case PENDING_READ_LOCK: > return "PENDING_READ"; > case PENDING_WRITE_LOCK: > return "PENDING_WRITE"; > default: > return "other"; > } >} > >const char *lock_flav_name(enum brl_flavour lock_flav) >{ > return (lock_flav == WINDOWS_LOCK) ? "WINDOWS_LOCK" : "POSIX_LOCK"; >} > >/**************************************************************************** > Utility function called to see if a file region is locked. > Called in the read/write codepath. >****************************************************************************/ > >bool is_locked(files_struct *fsp, > uint32 smbpid, > SMB_BIG_UINT count, > SMB_BIG_UINT offset, > enum brl_type lock_type) >{ > int strict_locking = lp_strict_locking(fsp->conn->params); > enum brl_flavour lock_flav = lp_posix_cifsu_locktype(fsp); > bool ret = True; > > if (count == 0) { > return False; > } > > if (!lp_locking(fsp->conn->params) || !strict_locking) { > return False; > } > > if (strict_locking == Auto) { > 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 = False; > } 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 = False; > } else { > struct byte_range_lock *br_lck = brl_get_locks_readonly(talloc_tos(), fsp); > if (!br_lck) { > return False; > } > ret = !brl_locktest(br_lck, > smbpid, > procid_self(), > offset, > count, > lock_type, > lock_flav); > TALLOC_FREE(br_lck); > } > } else { > struct byte_range_lock *br_lck = brl_get_locks_readonly(talloc_tos(), fsp); > if (!br_lck) { > return False; > } > ret = !brl_locktest(br_lck, > smbpid, > procid_self(), > offset, > count, > lock_type, > lock_flav); > TALLOC_FREE(br_lck); > } > > DEBUG(10,("is_locked: flavour = %s brl start=%.0f len=%.0f %s for fnum %d file %s\n", > lock_flav_name(lock_flav), > (double)offset, (double)count, ret ? "locked" : "unlocked", > fsp->fnum, fsp->fsp_name )); > > return ret; >} > >/**************************************************************************** > Find out if a lock could be granted - return who is blocking us if we can't. >****************************************************************************/ > >NTSTATUS query_lock(files_struct *fsp, > uint32 *psmbpid, > SMB_BIG_UINT *pcount, > SMB_BIG_UINT *poffset, > enum brl_type *plock_type, > enum brl_flavour lock_flav) >{ > struct byte_range_lock *br_lck = NULL; > NTSTATUS status = NT_STATUS_LOCK_NOT_GRANTED; > > if (!fsp->can_lock) { > return fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE; > } > > if (!lp_locking(fsp->conn->params)) { > return NT_STATUS_OK; > } > > br_lck = brl_get_locks_readonly(talloc_tos(), fsp); > if (!br_lck) { > return NT_STATUS_NO_MEMORY; > } > > status = brl_lockquery(br_lck, > psmbpid, > procid_self(), > poffset, > pcount, > plock_type, > lock_flav); > > TALLOC_FREE(br_lck); > return status; >} > >/**************************************************************************** > Utility function called by locking requests. >****************************************************************************/ > >struct byte_range_lock *do_lock(struct messaging_context *msg_ctx, > files_struct *fsp, > uint32 lock_pid, > SMB_BIG_UINT count, > SMB_BIG_UINT offset, > enum brl_type lock_type, > enum brl_flavour lock_flav, > bool blocking_lock, > NTSTATUS *perr, > uint32 *plock_pid) >{ > struct byte_range_lock *br_lck = NULL; > > if (!fsp->can_lock) { > *perr = fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE; > return NULL; > } > > if (!lp_locking(fsp->conn->params)) { > *perr = NT_STATUS_OK; > return NULL; > } > > /* NOTE! 0 byte long ranges ARE allowed and should be stored */ > > DEBUG(10,("do_lock: lock flavour %s lock type %s start=%.0f len=%.0f requested for fnum %d file %s\n", > lock_flav_name(lock_flav), lock_type_name(lock_type), > (double)offset, (double)count, fsp->fnum, fsp->fsp_name )); > > br_lck = brl_get_locks(talloc_tos(), fsp); > if (!br_lck) { > *perr = NT_STATUS_NO_MEMORY; > return NULL; > } > > *perr = brl_lock(msg_ctx, > br_lck, > lock_pid, > procid_self(), > offset, > count, > lock_type, > lock_flav, > blocking_lock, > plock_pid); > > if (lock_flav == WINDOWS_LOCK && > fsp->current_lock_count != NO_LOCKING_COUNT) { > /* blocking ie. pending, locks also count here, > * as this is an efficiency counter to avoid checking > * the lock db. on close. JRA. */ > > fsp->current_lock_count++; > } else { > /* Notice that this has had a POSIX lock request. > * We can't count locks after this so forget them. > */ > fsp->current_lock_count = NO_LOCKING_COUNT; > } > > return br_lck; >} > >/**************************************************************************** > Utility function called by unlocking requests. >****************************************************************************/ > >NTSTATUS do_unlock(struct messaging_context *msg_ctx, > files_struct *fsp, > uint32 lock_pid, > SMB_BIG_UINT count, > SMB_BIG_UINT offset, > enum brl_flavour lock_flav) >{ > bool ok = False; > struct byte_range_lock *br_lck = NULL; > > if (!fsp->can_lock) { > return fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE; > } > > if (!lp_locking(fsp->conn->params)) { > return NT_STATUS_OK; > } > > DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for fnum %d file %s\n", > (double)offset, (double)count, fsp->fnum, fsp->fsp_name )); > > br_lck = brl_get_locks(talloc_tos(), fsp); > if (!br_lck) { > return NT_STATUS_NO_MEMORY; > } > > ok = brl_unlock(msg_ctx, > br_lck, > lock_pid, > procid_self(), > offset, > count, > lock_flav); > > TALLOC_FREE(br_lck); > > if (!ok) { > DEBUG(10,("do_unlock: returning ERRlock.\n" )); > return NT_STATUS_RANGE_NOT_LOCKED; > } > > if (lock_flav == WINDOWS_LOCK && > fsp->current_lock_count != NO_LOCKING_COUNT) { > SMB_ASSERT(fsp->current_lock_count > 0); > fsp->current_lock_count--; > } > > return NT_STATUS_OK; >} > >/**************************************************************************** > Cancel any pending blocked locks. >****************************************************************************/ > >NTSTATUS do_lock_cancel(files_struct *fsp, > uint32 lock_pid, > SMB_BIG_UINT count, > SMB_BIG_UINT offset, > enum brl_flavour lock_flav) >{ > bool ok = False; > struct byte_range_lock *br_lck = NULL; > > if (!fsp->can_lock) { > return fsp->is_directory ? > NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE; > } > > if (!lp_locking(fsp->conn->params)) { > return NT_STATUS_DOS(ERRDOS, ERRcancelviolation); > } > > DEBUG(10,("do_lock_cancel: cancel start=%.0f len=%.0f requested for fnum %d file %s\n", > (double)offset, (double)count, fsp->fnum, fsp->fsp_name )); > > br_lck = brl_get_locks(talloc_tos(), fsp); > if (!br_lck) { > return NT_STATUS_NO_MEMORY; > } > > ok = brl_lock_cancel(br_lck, > lock_pid, > procid_self(), > offset, > count, > lock_flav); > > TALLOC_FREE(br_lck); > > if (!ok) { > DEBUG(10,("do_lock_cancel: returning ERRcancelviolation.\n" )); > return NT_STATUS_DOS(ERRDOS, ERRcancelviolation); > } > > if (lock_flav == WINDOWS_LOCK && > fsp->current_lock_count != NO_LOCKING_COUNT) { > SMB_ASSERT(fsp->current_lock_count > 0); > fsp->current_lock_count--; > } > > return NT_STATUS_OK; >} > >/**************************************************************************** > Remove any locks on this fd. Called from file_close(). >****************************************************************************/ > >void locking_close_file(struct messaging_context *msg_ctx, > files_struct *fsp) >{ > struct byte_range_lock *br_lck; > > if (!lp_locking(fsp->conn->params)) { > return; > } > > /* If we have not outstanding locks or pending > * locks then we don't need to look in the lock db. > */ > > if (fsp->current_lock_count == 0) { > return; > } > > br_lck = brl_get_locks(talloc_tos(),fsp); > > if (br_lck) { > cancel_pending_lock_requests_by_fid(fsp, br_lck); > brl_close_fnum(msg_ctx, br_lck); > TALLOC_FREE(br_lck); > } >} > >/**************************************************************************** > Initialise the locking functions. >****************************************************************************/ > >static bool locking_init_internal(bool read_only) >{ > brl_init(read_only); > > if (lock_db) > return True; > > lock_db = db_open(NULL, lock_path("locking.tdb"), > lp_open_files_db_hash_size(), > TDB_DEFAULT|TDB_VOLATILE|TDB_CLEAR_IF_FIRST, > read_only?O_RDONLY:O_RDWR|O_CREAT, 0644); > > if (!lock_db) { > DEBUG(0,("ERROR: Failed to initialise locking database\n")); > return False; > } > > if (!posix_locking_init(read_only)) > return False; > > return True; >} > >bool locking_init(void) >{ > return locking_init_internal(false); >} > >bool locking_init_readonly(void) >{ > return locking_init_internal(true); >} > >/******************************************************************* > Deinitialize the share_mode management. >******************************************************************/ > >bool locking_end(void) >{ > brl_shutdown(); > TALLOC_FREE(lock_db); > return true; >} > >/******************************************************************* > Form a static locking key for a dev/inode pair. >******************************************************************/ > >static TDB_DATA locking_key(const struct file_id *id, struct file_id *tmp) >{ > *tmp = *id; > return make_tdb_data((const uint8_t *)tmp, sizeof(*tmp)); >} > >/******************************************************************* > Print out a share mode. >********************************************************************/ > >char *share_mode_str(TALLOC_CTX *ctx, int num, const struct share_mode_entry *e) >{ > return talloc_asprintf(ctx, "share_mode_entry[%d]: %s " > "pid = %s, share_access = 0x%x, private_options = 0x%x, " > "access_mask = 0x%x, mid = 0x%x, type= 0x%x, gen_id = %lu, " > "uid = %u, flags = %u, file_id %s", > num, > e->op_type == UNUSED_SHARE_MODE_ENTRY ? "UNUSED" : "", > procid_str_static(&e->pid), > e->share_access, e->private_options, > e->access_mask, e->op_mid, e->op_type, e->share_file_id, > (unsigned int)e->uid, (unsigned int)e->flags, > file_id_string_tos(&e->id)); >} > >/******************************************************************* > Print out a share mode table. >********************************************************************/ > >static void print_share_mode_table(struct locking_data *data) >{ > int num_share_modes = data->u.s.num_share_mode_entries; > struct share_mode_entry *shares = > (struct share_mode_entry *)(data + 1); > int i; > > for (i = 0; i < num_share_modes; i++) { > struct share_mode_entry entry; > char *str; > > /* > * We need to memcpy the entry here due to alignment > * restrictions that are not met when directly accessing > * shares[i] > */ > > memcpy(&entry, &shares[i], sizeof(struct share_mode_entry)); > str = share_mode_str(talloc_tos(), i, &entry); > > DEBUG(10,("print_share_mode_table: %s\n", str ? str : "")); > TALLOC_FREE(str); > } >} > >/******************************************************************* > Get all share mode entries for a dev/inode pair. >********************************************************************/ > >static bool parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) >{ > struct locking_data data; > int i; > > if (dbuf.dsize < sizeof(struct locking_data)) { > smb_panic("parse_share_modes: buffer too short"); > } > > memcpy(&data, dbuf.dptr, sizeof(data)); > > lck->delete_on_close = data.u.s.delete_on_close; > lck->old_write_time = data.u.s.old_write_time; > lck->changed_write_time = data.u.s.changed_write_time; > lck->num_share_modes = data.u.s.num_share_mode_entries; > > DEBUG(10, ("parse_share_modes: delete_on_close: %d, owrt: %s, " > "cwrt: %s, tok: %u, num_share_modes: %d\n", > lck->delete_on_close, > timestring(debug_ctx(), > convert_timespec_to_time_t(lck->old_write_time)), > timestring(debug_ctx(), > convert_timespec_to_time_t( > lck->changed_write_time)), > (unsigned int)data.u.s.delete_token_size, > lck->num_share_modes)); > > if ((lck->num_share_modes < 0) || (lck->num_share_modes > 1000000)) { > DEBUG(0, ("invalid number of share modes: %d\n", > lck->num_share_modes)); > smb_panic("parse_share_modes: invalid number of share modes"); > } > > lck->share_modes = NULL; > > if (lck->num_share_modes != 0) { > > if (dbuf.dsize < (sizeof(struct locking_data) + > (lck->num_share_modes * > sizeof(struct share_mode_entry)))) { > smb_panic("parse_share_modes: buffer too short"); > } > > lck->share_modes = (struct share_mode_entry *) > TALLOC_MEMDUP(lck, > dbuf.dptr+sizeof(struct locking_data), > lck->num_share_modes * > sizeof(struct share_mode_entry)); > > if (lck->share_modes == NULL) { > smb_panic("parse_share_modes: talloc failed"); > } > } > > /* Get any delete token. */ > if (data.u.s.delete_token_size) { > uint8 *p = dbuf.dptr + sizeof(struct locking_data) + > (lck->num_share_modes * > sizeof(struct share_mode_entry)); > > if ((data.u.s.delete_token_size < sizeof(uid_t) + sizeof(gid_t)) || > ((data.u.s.delete_token_size - sizeof(uid_t)) % sizeof(gid_t)) != 0) { > DEBUG(0, ("parse_share_modes: invalid token size %d\n", > data.u.s.delete_token_size)); > smb_panic("parse_share_modes: invalid token size"); > } > > lck->delete_token = TALLOC_P(lck, UNIX_USER_TOKEN); > if (!lck->delete_token) { > smb_panic("parse_share_modes: talloc failed"); > } > > /* Copy out the uid and gid. */ > memcpy(&lck->delete_token->uid, p, sizeof(uid_t)); > p += sizeof(uid_t); > memcpy(&lck->delete_token->gid, p, sizeof(gid_t)); > p += sizeof(gid_t); > > /* Any supplementary groups ? */ > lck->delete_token->ngroups = (data.u.s.delete_token_size > (sizeof(uid_t) + sizeof(gid_t))) ? > ((data.u.s.delete_token_size - > (sizeof(uid_t) + sizeof(gid_t)))/sizeof(gid_t)) : 0; > > if (lck->delete_token->ngroups) { > /* Make this a talloc child of lck->delete_token. */ > lck->delete_token->groups = TALLOC_ARRAY(lck->delete_token, gid_t, > lck->delete_token->ngroups); > if (!lck->delete_token) { > smb_panic("parse_share_modes: talloc failed"); > } > > for (i = 0; i < lck->delete_token->ngroups; i++) { > memcpy(&lck->delete_token->groups[i], p, sizeof(gid_t)); > p += sizeof(gid_t); > } > } > > } else { > lck->delete_token = NULL; > } > > /* Save off the associated service path and filename. */ > lck->servicepath = (const char *)dbuf.dptr + sizeof(struct locking_data) + > (lck->num_share_modes * sizeof(struct share_mode_entry)) + > data.u.s.delete_token_size; > > lck->filename = (const char *)dbuf.dptr + sizeof(struct locking_data) + > (lck->num_share_modes * sizeof(struct share_mode_entry)) + > data.u.s.delete_token_size + > strlen(lck->servicepath) + 1; > > /* > * Ensure that each entry has a real process attached. > */ > > for (i = 0; i < lck->num_share_modes; i++) { > struct share_mode_entry *entry_p = &lck->share_modes[i]; > char *str = NULL; > if (DEBUGLEVEL >= 10) { > str = share_mode_str(NULL, i, entry_p); > } > DEBUG(10,("parse_share_modes: %s\n", > str ? str : "")); > if (!process_exists(entry_p->pid)) { > DEBUG(10,("parse_share_modes: deleted %s\n", > str ? str : "")); > entry_p->op_type = UNUSED_SHARE_MODE_ENTRY; > lck->modified = True; > } > TALLOC_FREE(str); > } > > return True; >} > >static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) >{ > TDB_DATA result; > int num_valid = 0; > int i; > struct locking_data *data; > ssize_t offset; > ssize_t sp_len; > uint32 delete_token_size; > > result.dptr = NULL; > result.dsize = 0; > > for (i=0; i<lck->num_share_modes; i++) { > if (!is_unused_share_mode_entry(&lck->share_modes[i])) { > num_valid += 1; > } > } > > if (num_valid == 0) { > return result; > } > > sp_len = strlen(lck->servicepath); > delete_token_size = (lck->delete_token ? > (sizeof(uid_t) + sizeof(gid_t) + (lck->delete_token->ngroups*sizeof(gid_t))) : 0); > > result.dsize = sizeof(*data) + > lck->num_share_modes * sizeof(struct share_mode_entry) + > delete_token_size + > sp_len + 1 + > strlen(lck->filename) + 1; > result.dptr = TALLOC_ARRAY(lck, uint8, result.dsize); > > if (result.dptr == NULL) { > smb_panic("talloc failed"); > } > > 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; > data->u.s.old_write_time = lck->old_write_time; > data->u.s.changed_write_time = lck->changed_write_time; > data->u.s.delete_token_size = delete_token_size; > > DEBUG(10,("unparse_share_modes: del: %d, owrt: %s cwrt: %s, tok: %u, " > "num: %d\n", data->u.s.delete_on_close, > timestring(debug_ctx(), > convert_timespec_to_time_t(lck->old_write_time)), > timestring(debug_ctx(), > convert_timespec_to_time_t( > lck->changed_write_time)), > (unsigned int)data->u.s.delete_token_size, > 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; > > /* Store any delete on close token. */ > if (lck->delete_token) { > uint8 *p = result.dptr + offset; > > memcpy(p, &lck->delete_token->uid, sizeof(uid_t)); > p += sizeof(uid_t); > > memcpy(p, &lck->delete_token->gid, sizeof(gid_t)); > p += sizeof(gid_t); > > for (i = 0; i < lck->delete_token->ngroups; i++) { > memcpy(p, &lck->delete_token->groups[i], sizeof(gid_t)); > p += sizeof(gid_t); > } > offset = p - result.dptr; > } > > safe_strcpy((char *)result.dptr + offset, lck->servicepath, > result.dsize - offset - 1); > offset += sp_len + 1; > safe_strcpy((char *)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(struct share_mode_lock *lck) >{ > NTSTATUS status; > TDB_DATA data; > > if (!lck->modified) { > return 0; > } > > data = unparse_share_modes(lck); > > if (data.dptr == NULL) { > if (!lck->fresh) { > /* There has been an entry before, delete it */ > > status = lck->record->delete_rec(lck->record); > if (!NT_STATUS_IS_OK(status)) { > DEBUG(0, ("delete_rec returned %s\n", > nt_errstr(status))); > smb_panic("could not delete share entry"); > } > } > goto done; > } > > status = lck->record->store(lck->record, data, TDB_REPLACE); > if (!NT_STATUS_IS_OK(status)) { > DEBUG(0, ("store returned %s\n", nt_errstr(status))); > smb_panic("could not store share mode entry"); > } > > done: > > return 0; >} > >static bool fill_share_mode_lock(struct share_mode_lock *lck, > struct file_id id, > const char *servicepath, > const char *fname, > TDB_DATA share_mode_data, > const struct timespec *old_write_time) >{ > /* 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->id = id; > lck->num_share_modes = 0; > lck->share_modes = NULL; > lck->delete_token = NULL; > lck->delete_on_close = False; > ZERO_STRUCT(lck->old_write_time); > ZERO_STRUCT(lck->changed_write_time); > lck->fresh = False; > lck->modified = False; > > lck->fresh = (share_mode_data.dptr == NULL); > > if (lck->fresh) { > if (fname == NULL || servicepath == NULL > || old_write_time == NULL) { > return False; > } > lck->filename = talloc_strdup(lck, fname); > lck->servicepath = talloc_strdup(lck, servicepath); > if (lck->filename == NULL || lck->servicepath == NULL) { > DEBUG(0, ("talloc failed\n")); > return False; > } > lck->old_write_time = *old_write_time; > } else { > if (!parse_share_modes(share_mode_data, lck)) { > DEBUG(0, ("Could not parse share modes\n")); > return False; > } > } > > return True; >} > >struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, > const struct file_id id, > const char *servicepath, > const char *fname, > const struct timespec *old_write_time) >{ > struct share_mode_lock *lck; > struct file_id tmp; > TDB_DATA key = locking_key(&id, &tmp); > > if (!(lck = TALLOC_P(mem_ctx, struct share_mode_lock))) { > DEBUG(0, ("talloc failed\n")); > return NULL; > } > > if (!(lck->record = lock_db->fetch_locked(lock_db, lck, key))) { > DEBUG(3, ("Could not lock share entry\n")); > TALLOC_FREE(lck); > return NULL; > } > > if (!fill_share_mode_lock(lck, id, servicepath, fname, > lck->record->value, old_write_time)) { > DEBUG(3, ("fill_share_mode_lock failed\n")); > TALLOC_FREE(lck); > return NULL; > } > > talloc_set_destructor(lck, share_mode_lock_destructor); > > return lck; >} > >struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx, > const struct file_id id, > const char *servicepath, > const char *fname) >{ > struct share_mode_lock *lck; > struct file_id tmp; > TDB_DATA key = locking_key(&id, &tmp); > TDB_DATA data; > > if (!(lck = TALLOC_P(mem_ctx, struct share_mode_lock))) { > DEBUG(0, ("talloc failed\n")); > return NULL; > } > > if (lock_db->fetch(lock_db, lck, key, &data) == -1) { > DEBUG(3, ("Could not fetch share entry\n")); > TALLOC_FREE(lck); > return NULL; > } > > if (!fill_share_mode_lock(lck, id, servicepath, fname, data, NULL)) { > DEBUG(3, ("fill_share_mode_lock failed\n")); > TALLOC_FREE(lck); > return NULL; > } > > return lck; >} > >/******************************************************************* > Sets the service name and filename for rename. > At this point we emit "file renamed" messages to all > process id's that have this file open. > Based on an initial code idea from SATOH Fumiyasu <fumiya@samba.gr.jp> >********************************************************************/ > >bool rename_share_filename(struct messaging_context *msg_ctx, > struct share_mode_lock *lck, > const char *servicepath, > const char *newname) >{ > size_t sp_len; > size_t fn_len; > size_t msg_len; > char *frm = NULL; > int i; > > DEBUG(10, ("rename_share_filename: servicepath %s newname %s\n", > servicepath, newname)); > > /* > * rename_internal_fsp() and rename_internals() add './' to > * head of newname if newname does not contain a '/'. > */ > while (newname[0] && newname[1] && newname[0] == '.' && newname[1] == '/') { > newname += 2; > } > > lck->servicepath = talloc_strdup(lck, servicepath); > lck->filename = talloc_strdup(lck, newname); > if (lck->filename == NULL || lck->servicepath == NULL) { > DEBUG(0, ("rename_share_filename: talloc failed\n")); > return False; > } > lck->modified = True; > > sp_len = strlen(lck->servicepath); > fn_len = strlen(lck->filename); > > msg_len = MSG_FILE_RENAMED_MIN_SIZE + sp_len + 1 + fn_len + 1; > > /* Set up the name changed message. */ > frm = TALLOC_ARRAY(lck, char, msg_len); > if (!frm) { > return False; > } > > push_file_id_16(frm, &lck->id); > > DEBUG(10,("rename_share_filename: msg_len = %u\n", (unsigned int)msg_len )); > > safe_strcpy(&frm[16], lck->servicepath, sp_len); > safe_strcpy(&frm[16 + sp_len + 1], lck->filename, fn_len); > > /* Send the messages. */ > for (i=0; i<lck->num_share_modes; i++) { > struct share_mode_entry *se = &lck->share_modes[i]; > if (!is_valid_share_mode_entry(se)) { > continue; > } > /* But not to ourselves... */ > if (procid_is_me(&se->pid)) { > continue; > } > > DEBUG(10,("rename_share_filename: sending rename message to pid %s " > "file_id %s sharepath %s newname %s\n", > procid_str_static(&se->pid), > file_id_string_tos(&lck->id), > lck->servicepath, lck->filename )); > > messaging_send_buf(msg_ctx, se->pid, MSG_SMB_FILE_RENAME, > (uint8 *)frm, msg_len); > } > > return True; >} > >void get_file_infos(struct file_id id, > bool *delete_on_close, > struct timespec *write_time) >{ > struct share_mode_lock *lck; > > if (delete_on_close) { > *delete_on_close = false; > } > > if (write_time) { > ZERO_STRUCTP(write_time); > } > > if (!(lck = fetch_share_mode_unlocked(talloc_tos(), id, NULL, NULL))) { > return; > } > > if (delete_on_close) { > *delete_on_close = lck->delete_on_close; > } > > if (write_time) { > struct timespec wt; > > wt = lck->changed_write_time; > if (null_timespec(wt)) { > wt = lck->old_write_time; > } > > *write_time = wt; > } > > TALLOC_FREE(lck); >} > >bool is_valid_share_mode_entry(const struct share_mode_entry *e) >{ > int num_props = 0; > > if (e->op_type == UNUSED_SHARE_MODE_ENTRY) { > /* cope with dead entries from the process not > existing. These should not be considered valid, > otherwise we end up doing zero timeout sharing > violation */ > return False; > } > > 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, > uid_t uid, 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->id = fsp->file_id; > e->share_file_id = fsp->fh->gen_id; > e->uid = (uint32)uid; > e->flags = fsp->posix_open ? SHARE_MODE_FLAG_POSIX_OPEN : 0; >} > >static void fill_deferred_open_entry(struct share_mode_entry *e, > const struct timeval request_time, > struct file_id id, 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->id = id; > e->uid = (uint32)-1; > e->flags = 0; >} > >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, > uid_t uid, uint16 mid, uint16 op_type, bool initial_delete_on_close_allowed) >{ > struct share_mode_entry entry; > fill_share_mode_entry(&entry, fsp, uid, mid, op_type); > if (initial_delete_on_close_allowed) { > entry.flags |= SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE; > } > add_share_mode_entry(lck, &entry); >} > >void add_deferred_open(struct share_mode_lock *lck, uint16 mid, > struct timeval request_time, > struct file_id id) >{ > struct share_mode_entry entry; > fill_deferred_open_entry(&entry, request_time, id, mid); > add_share_mode_entry(lck, &entry); >} > >/******************************************************************* > Check if two share mode entries are identical, ignoring oplock > and mid info and desired_access. (Removed paranoia test - it's > not automatically a logic error if they are identical. JRA.) >********************************************************************/ > >static bool share_modes_identical(struct share_mode_entry *e1, > struct share_mode_entry *e2) >{ > /* We used to check for e1->share_access == e2->share_access here > as well as the other fields but 2 different DOS or FCB opens > sharing the same share mode entry may validly differ in > fsp->share_access field. */ > > return (procid_equal(&e1->pid, &e2->pid) && > file_id_equal(&e1->id, &e2->id) && > 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) && > file_id_equal(&e1->id, &e2->id)); >} > >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; > > /* Don't care about the pid owner being correct here - just a search. */ > fill_share_mode_entry(&entry, fsp, (uid_t)-1, 0, NO_OPLOCK); > > 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->id, 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; > > /* Don't care about the pid owner being correct here - just a search. */ > fill_share_mode_entry(&entry, fsp, (uid_t)-1, 0, NO_OPLOCK); > > 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; > > /* Don't care about the pid owner being correct here - just a search. */ > fill_share_mode_entry(&entry, fsp, (uid_t)-1, 0, NO_OPLOCK); > > 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_ntcreate. 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; > } > > /* Don't allow delete on close for non-empty directories. */ > if (fsp->is_directory) { > return can_delete_directory(fsp->conn, fsp->fsp_name); > } > > return NT_STATUS_OK; >} > >/**************************************************************************** > Do we have an open file handle that created this entry ? >****************************************************************************/ > >bool can_set_initial_delete_on_close(const struct share_mode_lock *lck) >{ > int i; > > for (i=0; i<lck->num_share_modes; i++) { > if (lck->share_modes[i].flags & SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE) { > return True; > } > } > return False; >} > >/************************************************************************* > Return a talloced copy of a UNIX_USER_TOKEN. NULL on fail. > (Should this be in locking.c.... ?). >*************************************************************************/ > >static UNIX_USER_TOKEN *copy_unix_token(TALLOC_CTX *ctx, UNIX_USER_TOKEN *tok) >{ > UNIX_USER_TOKEN *cpy; > > if (tok == NULL) { > return NULL; > } > > cpy = TALLOC_P(ctx, UNIX_USER_TOKEN); > if (!cpy) { > return NULL; > } > > cpy->uid = tok->uid; > cpy->gid = tok->gid; > cpy->ngroups = tok->ngroups; > if (tok->ngroups) { > /* Make this a talloc child of cpy. */ > cpy->groups = TALLOC_ARRAY(cpy, gid_t, tok->ngroups); > if (!cpy->groups) { > return NULL; > } > memcpy(cpy->groups, tok->groups, tok->ngroups * sizeof(gid_t)); > } > return cpy; >} > >/**************************************************************************** > Replace the delete on close token. >****************************************************************************/ > >void set_delete_on_close_token(struct share_mode_lock *lck, UNIX_USER_TOKEN *tok) >{ > TALLOC_FREE(lck->delete_token); /* Also deletes groups... */ > > /* Copy the new token (can be NULL). */ > lck->delete_token = copy_unix_token(lck, tok); > lck->modified = True; >} > >/**************************************************************************** > 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. > This makes a copy of any UNIX_USER_TOKEN into the > lck entry. This function is used when the lock is already granted. >****************************************************************************/ > >void set_delete_on_close_lck(struct share_mode_lock *lck, bool delete_on_close, UNIX_USER_TOKEN *tok) >{ > if (lck->delete_on_close != delete_on_close) { > set_delete_on_close_token(lck, tok); > lck->delete_on_close = delete_on_close; > if (delete_on_close) { > SMB_ASSERT(lck->delete_token != NULL); > } > lck->modified = True; > } >} > >bool set_delete_on_close(files_struct *fsp, bool delete_on_close, UNIX_USER_TOKEN *tok) >{ > 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(talloc_tos(), fsp->file_id, NULL, NULL, > NULL); > if (lck == NULL) { > return False; > } > > set_delete_on_close_lck(lck, delete_on_close, tok); > > if (fsp->is_directory) { > send_stat_cache_delete_message(fsp->fsp_name); > } > > TALLOC_FREE(lck); > return True; >} > >/**************************************************************************** > Sets the allow initial delete on close flag for this share mode. >****************************************************************************/ > >bool set_allow_initial_delete_on_close(struct share_mode_lock *lck, files_struct *fsp, bool delete_on_close) >{ > struct share_mode_entry entry, *e; > > /* Don't care about the pid owner being correct here - just a search. */ > fill_share_mode_entry(&entry, fsp, (uid_t)-1, 0, NO_OPLOCK); > > e = find_share_mode_entry(lck, &entry); > if (e == NULL) { > return False; > } > > if (delete_on_close) { > e->flags |= SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE; > } else { > e->flags &= ~SHARE_MODE_ALLOW_INITIAL_DELETE_ON_CLOSE; > } > lck->modified = True; > return True; >} > >bool set_write_time(struct file_id fileid, struct timespec write_time, > bool overwrite) >{ > struct share_mode_lock *lck; > > DEBUG(5,("set_write_time: %s overwrite=%d id=%s\n", > timestring(debug_ctx(), > convert_timespec_to_time_t(write_time)), > overwrite, file_id_string_tos(&fileid))); > > lck = get_share_mode_lock(NULL, fileid, NULL, NULL, NULL); > if (lck == NULL) { > return False; > } > > if (overwrite || null_timespec(lck->changed_write_time)) { > lck->modified = True; > lck->changed_write_time = write_time; > } > > TALLOC_FREE(lck); > return True; >} > >struct forall_state { > void (*fn)(const struct share_mode_entry *entry, > const char *sharepath, > const char *fname, > void *private_data); > void *private_data; >}; > >static int traverse_fn(struct db_record *rec, void *_state) >{ > struct forall_state *state = (struct forall_state *)_state; > struct locking_data *data; > struct share_mode_entry *shares; > const char *sharepath; > const char *fname; > int i; > > /* Ensure this is a locking_key record. */ > if (rec->key.dsize != sizeof(struct file_id)) > return 0; > > data = (struct locking_data *)rec->value.dptr; > shares = (struct share_mode_entry *)(rec->value.dptr + sizeof(*data)); > sharepath = (const char *)rec->value.dptr + sizeof(*data) + > data->u.s.num_share_mode_entries*sizeof(*shares) + > data->u.s.delete_token_size; > fname = (const char *)rec->value.dptr + sizeof(*data) + > data->u.s.num_share_mode_entries*sizeof(*shares) + > data->u.s.delete_token_size + > strlen(sharepath) + 1; > > for (i=0;i<data->u.s.num_share_mode_entries;i++) { > state->fn(&shares[i], sharepath, fname, > state->private_data); > } > 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 *, void *), > void *private_data) >{ > struct forall_state state; > > if (lock_db == NULL) > return 0; > > state.fn = fn; > state.private_data = private_data; > > return lock_db->traverse_read(lock_db, traverse_fn, (void *)&state); >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 5512
:
3382
|
3389
|
3392
| 3393 |
3867