X-Git-Url: http://git.samba.org/?p=samba.git;a=blobdiff_plain;f=source3%2Flocking%2Flocking.c;h=55412ec8b2aa8c702db98b739d6e6fe2f64b276c;hp=17131d9194bf5ab2b2d006a28842850369ba4a3b;hb=3d15137653a7d1b593a9af2eef12f6e5b9a04c4f;hpb=b430b382202858a6c52c1cacbb91910b2dd7e16c diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 17131d9194b..55412ec8b2a 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -4,17 +4,17 @@ 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 . @@ -36,6 +36,14 @@ */ #include "includes.h" +#include "system/filesys.h" +#include "locking/proto.h" +#include "smbd/globals.h" +#include "dbwrap.h" +#include "../libcli/security/security.h" +#include "serverid.h" +#include "messages.h" +#include "util_tdb.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_LOCKING @@ -75,82 +83,103 @@ const char *lock_flav_name(enum brl_flavour lock_flav) 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) +void init_strict_lock_struct(files_struct *fsp, + uint64_t smblctx, + br_off start, + br_off size, + enum brl_type lock_type, + struct lock_struct *plock) +{ + SMB_ASSERT(lock_type == READ_LOCK || lock_type == WRITE_LOCK); + + plock->context.smblctx = smblctx; + plock->context.tid = fsp->conn->cnum; + plock->context.pid = sconn_server_id(fsp->conn->sconn); + plock->start = start; + plock->size = size; + plock->fnum = fsp->fnum; + plock->lock_type = lock_type; + plock->lock_flav = lp_posix_cifsu_locktype(fsp); +} + +bool strict_lock_default(files_struct *fsp, struct lock_struct *plock) { 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; + bool ret = False; + + if (plock->size == 0) { + return True; } if (!lp_locking(fsp->conn->params) || !strict_locking) { - return False; + return True; } 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; + if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && (plock->lock_type == READ_LOCK || plock->lock_type == WRITE_LOCK)) { + DEBUG(10,("is_locked: optimisation - exclusive oplock on file %s\n", fsp_str_dbg(fsp))); + ret = True; } 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; + (plock->lock_type == READ_LOCK)) { + DEBUG(10,("is_locked: optimisation - level II oplock on file %s\n", fsp_str_dbg(fsp))); + ret = True; } else { - struct byte_range_lock *br_lck = brl_get_locks_readonly(talloc_tos(), fsp); + struct byte_range_lock *br_lck; + + br_lck = brl_get_locks_readonly(fsp); if (!br_lck) { - return False; + return True; } - ret = !brl_locktest(br_lck, - smbpid, - procid_self(), - offset, - count, - lock_type, - lock_flav); - TALLOC_FREE(br_lck); + ret = brl_locktest(br_lck, + plock->context.smblctx, + plock->context.pid, + plock->start, + plock->size, + plock->lock_type, + plock->lock_flav); } } else { - struct byte_range_lock *br_lck = brl_get_locks_readonly(talloc_tos(), fsp); + struct byte_range_lock *br_lck; + + br_lck = brl_get_locks_readonly(fsp); if (!br_lck) { - return False; + return True; } - 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 )); + ret = brl_locktest(br_lck, + plock->context.smblctx, + plock->context.pid, + plock->start, + plock->size, + plock->lock_type, + plock->lock_flav); + } + + DEBUG(10,("strict_lock_default: flavour = %s brl start=%.0f " + "len=%.0f %s for fnum %d file %s\n", + lock_flav_name(plock->lock_flav), + (double)plock->start, (double)plock->size, + ret ? "unlocked" : "locked", + plock->fnum, fsp_str_dbg(fsp))); return ret; } +void strict_unlock_default(files_struct *fsp, struct lock_struct *plock) +{ +} + /**************************************************************************** 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, + uint64_t *psmblctx, + uint64_t *pcount, + uint64_t *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; @@ -160,21 +189,46 @@ NTSTATUS query_lock(files_struct *fsp, return NT_STATUS_OK; } - br_lck = brl_get_locks_readonly(talloc_tos(), fsp); + br_lck = brl_get_locks_readonly(fsp); if (!br_lck) { return NT_STATUS_NO_MEMORY; } - status = brl_lockquery(br_lck, - psmbpid, - procid_self(), + return brl_lockquery(br_lck, + psmblctx, + sconn_server_id(fsp->conn->sconn), poffset, pcount, plock_type, lock_flav); +} - TALLOC_FREE(br_lck); - return status; +static void increment_current_lock_count(files_struct *fsp, + enum brl_flavour lock_flav) +{ + 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; + } +} + +static void decrement_current_lock_count(files_struct *fsp, + enum brl_flavour lock_flav) +{ + if (lock_flav == WINDOWS_LOCK && + fsp->current_lock_count != NO_LOCKING_COUNT) { + SMB_ASSERT(fsp->current_lock_count > 0); + fsp->current_lock_count--; + } } /**************************************************************************** @@ -183,17 +237,24 @@ NTSTATUS query_lock(files_struct *fsp, 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, + uint64_t smblctx, + uint64_t count, + uint64_t offset, enum brl_type lock_type, enum brl_flavour lock_flav, bool blocking_lock, NTSTATUS *perr, - uint32 *plock_pid) + uint64_t *psmblctx, + struct blocking_lock_record *blr) { struct byte_range_lock *br_lck = NULL; + /* silently return ok on print files as we don't do locking there */ + if (fsp->print_file) { + *perr = NT_STATUS_OK; + return NULL; + } + if (!fsp->can_lock) { *perr = fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE; return NULL; @@ -206,9 +267,11 @@ struct byte_range_lock *do_lock(struct messaging_context *msg_ctx, /* 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", + DEBUG(10,("do_lock: lock flavour %s lock type %s start=%.0f len=%.0f " + "blocking_lock=%s 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 )); + (double)offset, (double)count, blocking_lock ? "true" : + "false", fsp->fnum, fsp_str_dbg(fsp))); br_lck = brl_get_locks(talloc_tos(), fsp); if (!br_lck) { @@ -218,29 +281,19 @@ struct byte_range_lock *do_lock(struct messaging_context *msg_ctx, *perr = brl_lock(msg_ctx, br_lck, - lock_pid, - procid_self(), + smblctx, + sconn_server_id(fsp->conn->sconn), offset, - count, + count, lock_type, lock_flav, blocking_lock, - plock_pid); + psmblctx, + blr); - 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; - } + DEBUG(10, ("do_lock: returning status=%s\n", nt_errstr(*perr))); + increment_current_lock_count(fsp, lock_flav); return br_lck; } @@ -250,24 +303,25 @@ struct byte_range_lock *do_lock(struct messaging_context *msg_ctx, NTSTATUS do_unlock(struct messaging_context *msg_ctx, files_struct *fsp, - uint32 lock_pid, - SMB_BIG_UINT count, - SMB_BIG_UINT offset, + uint64_t smblctx, + uint64_t count, + uint64_t 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 )); + (double)offset, (double)count, fsp->fnum, + fsp_str_dbg(fsp))); br_lck = brl_get_locks(talloc_tos(), fsp); if (!br_lck) { @@ -276,12 +330,12 @@ NTSTATUS do_unlock(struct messaging_context *msg_ctx, ok = brl_unlock(msg_ctx, br_lck, - lock_pid, - procid_self(), + smblctx, + sconn_server_id(fsp->conn->sconn), offset, count, lock_flav); - + TALLOC_FREE(br_lck); if (!ok) { @@ -289,12 +343,7 @@ NTSTATUS do_unlock(struct messaging_context *msg_ctx, 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--; - } - + decrement_current_lock_count(fsp, lock_flav); return NT_STATUS_OK; } @@ -303,25 +352,27 @@ NTSTATUS do_unlock(struct messaging_context *msg_ctx, ****************************************************************************/ NTSTATUS do_lock_cancel(files_struct *fsp, - uint32 lock_pid, - SMB_BIG_UINT count, - SMB_BIG_UINT offset, - enum brl_flavour lock_flav) + uint64 smblctx, + uint64_t count, + uint64_t offset, + enum brl_flavour lock_flav, + struct blocking_lock_record *blr) { 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 )); + (double)offset, (double)count, fsp->fnum, + fsp_str_dbg(fsp))); br_lck = brl_get_locks(talloc_tos(), fsp); if (!br_lck) { @@ -329,12 +380,13 @@ NTSTATUS do_lock_cancel(files_struct *fsp, } ok = brl_lock_cancel(br_lck, - lock_pid, - procid_self(), + smblctx, + sconn_server_id(fsp->conn->sconn), offset, count, - lock_flav); - + lock_flav, + blr); + TALLOC_FREE(br_lck); if (!ok) { @@ -342,12 +394,7 @@ NTSTATUS do_lock_cancel(files_struct *fsp, 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--; - } - + decrement_current_lock_count(fsp, lock_flav); return NT_STATUS_OK; } @@ -356,7 +403,8 @@ NTSTATUS do_lock_cancel(files_struct *fsp, ****************************************************************************/ void locking_close_file(struct messaging_context *msg_ctx, - files_struct *fsp) + files_struct *fsp, + enum file_close_type close_type) { struct byte_range_lock *br_lck; @@ -375,7 +423,7 @@ void locking_close_file(struct messaging_context *msg_ctx, br_lck = brl_get_locks(talloc_tos(),fsp); if (br_lck) { - cancel_pending_lock_requests_by_fid(fsp, br_lck); + cancel_pending_lock_requests_by_fid(fsp, br_lck, close_type); brl_close_fnum(msg_ctx, br_lck); TALLOC_FREE(br_lck); } @@ -394,7 +442,7 @@ static bool locking_init_internal(bool read_only) lock_db = db_open(NULL, lock_path("locking.tdb"), lp_open_files_db_hash_size(), - TDB_DEFAULT|TDB_VOLATILE|TDB_CLEAR_IF_FIRST, + TDB_DEFAULT|TDB_VOLATILE|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, read_only?O_RDONLY:O_RDWR|O_CREAT, 0644); if (!lock_db) { @@ -443,19 +491,21 @@ static TDB_DATA locking_key(const struct file_id *id, struct file_id *tmp) Print out a share mode. ********************************************************************/ -char *share_mode_str(TALLOC_CTX *ctx, int num, struct share_mode_entry *e) +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", + "access_mask = 0x%x, mid = 0x%llx, type= 0x%x, gen_id = %lu, " + "uid = %u, flags = %u, file_id %s, name_hash = 0x%x", 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, + e->access_mask, (unsigned long long)e->op_mid, + e->op_type, e->share_file_id, (unsigned int)e->uid, (unsigned int)e->flags, - file_id_string_tos(&e->id)); + file_id_string_tos(&e->id), + (unsigned int)e->name_hash); } /******************************************************************* @@ -487,35 +537,132 @@ static void print_share_mode_table(struct locking_data *data) } } +static int parse_delete_tokens_list(struct share_mode_lock *lck, + struct locking_data *pdata, + const TDB_DATA dbuf) +{ + uint8_t *p = dbuf.dptr + sizeof(struct locking_data) + + (lck->num_share_modes * + sizeof(struct share_mode_entry)); + uint8_t *end_ptr = dbuf.dptr + (dbuf.dsize - 2); + int delete_tokens_size = 0; + int i; + + lck->delete_tokens = NULL; + + for (i = 0; i < pdata->u.s.num_delete_token_entries; i++) { + uint32_t token_len; + struct delete_token_list *pdtl; + + if (end_ptr - p < (sizeof(uint32_t) + sizeof(uint32_t) + + sizeof(uid_t) + sizeof(gid_t))) { + DEBUG(0,("parse_delete_tokens_list: " + "corrupt token list (%u)", + (unsigned int)(end_ptr - p))); + smb_panic("corrupt token list"); + return -1; + } + + memcpy(&token_len, p, sizeof(token_len)); + delete_tokens_size += token_len; + + if (p + token_len > end_ptr || token_len < sizeof(token_len) + + sizeof(pdtl->name_hash) + + sizeof(uid_t) + + sizeof(gid_t)) { + DEBUG(0,("parse_delete_tokens_list: " + "invalid token length (%u)\n", + (unsigned int)token_len )); + smb_panic("invalid token length"); + return -1; + } + + p += sizeof(token_len); + + pdtl = TALLOC_ZERO_P(lck, struct delete_token_list); + if (pdtl == NULL) { + DEBUG(0,("parse_delete_tokens_list: talloc failed")); + return -1; + } + /* Copy out the name_hash. */ + memcpy(&pdtl->name_hash, p, sizeof(pdtl->name_hash)); + p += sizeof(pdtl->name_hash); + + pdtl->delete_token = TALLOC_ZERO_P(pdtl, struct security_unix_token); + if (pdtl->delete_token == NULL) { + DEBUG(0,("parse_delete_tokens_list: talloc failed")); + return -1; + } + + /* Copy out the uid and gid. */ + memcpy(&pdtl->delete_token->uid, p, sizeof(uid_t)); + p += sizeof(uid_t); + memcpy(&pdtl->delete_token->gid, p, sizeof(gid_t)); + p += sizeof(gid_t); + + token_len -= (sizeof(token_len) + sizeof(pdtl->name_hash) + + sizeof(uid_t) + sizeof(gid_t)); + + /* Any supplementary groups ? */ + if (token_len) { + int j; + + if (token_len % sizeof(gid_t) != 0) { + DEBUG(0,("parse_delete_tokens_list: " + "corrupt group list (%u)", + (unsigned int)(token_len % sizeof(gid_t)) )); + smb_panic("corrupt group list"); + return -1; + } + + pdtl->delete_token->ngroups = token_len / sizeof(gid_t); + pdtl->delete_token->groups = talloc_array(pdtl->delete_token, gid_t, + pdtl->delete_token->ngroups); + if (pdtl->delete_token->groups == NULL) { + DEBUG(0,("parse_delete_tokens_list: talloc failed")); + return -1; + } + + for (j = 0; j < pdtl->delete_token->ngroups; j++) { + memcpy(&pdtl->delete_token->groups[j], p, sizeof(gid_t)); + p += sizeof(gid_t); + } + } + /* Add to the list. */ + DLIST_ADD(lck->delete_tokens, pdtl); + } + + return delete_tokens_size; +} + /******************************************************************* Get all share mode entries for a dev/inode pair. ********************************************************************/ -static bool parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) +static bool parse_share_modes(const TDB_DATA dbuf, struct share_mode_lock *lck) { - struct locking_data *data; + struct locking_data data; + int delete_tokens_size; int i; if (dbuf.dsize < sizeof(struct locking_data)) { smb_panic("parse_share_modes: buffer too short"); } - data = (struct locking_data *)dbuf.dptr; + 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; + 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(), + DEBUG(10, ("parse_share_modes: owrt: %s, " + "cwrt: %s, ntok: %u, num_share_modes: %d\n", + timestring(talloc_tos(), convert_timespec_to_time_t(lck->old_write_time)), - timestring(debug_ctx(), + timestring(talloc_tos(), convert_timespec_to_time_t( lck->changed_write_time)), - (unsigned int)data->u.s.delete_token_size, + (unsigned int)data.u.s.num_delete_token_entries, lck->num_share_modes)); if ((lck->num_share_modes < 0) || (lck->num_share_modes > 1000000)) { @@ -525,7 +672,7 @@ static bool parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) } lck->share_modes = NULL; - + if (lck->num_share_modes != 0) { if (dbuf.dsize < (sizeof(struct locking_data) + @@ -533,9 +680,10 @@ static bool parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) 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(*data), + TALLOC_MEMDUP(lck, + dbuf.dptr+sizeof(struct locking_data), lck->num_share_modes * sizeof(struct share_mode_entry)); @@ -544,63 +692,28 @@ static bool parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) } } - /* Get any delete token. */ - if (data->u.s.delete_token_size) { - uint8 *p = dbuf.dptr + sizeof(*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; + /* Get any delete tokens. */ + delete_tokens_size = parse_delete_tokens_list(lck, &data, dbuf); + if (delete_tokens_size < 0) { + smb_panic("parse_share_modes: parse_delete_tokens_list failed"); } /* Save off the associated service path and filename. */ - lck->servicepath = (const char *)dbuf.dptr + sizeof(*data) + + 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; + delete_tokens_size; - lck->filename = (const char *)dbuf.dptr + sizeof(*data) + + lck->base_name = (const char *)dbuf.dptr + sizeof(struct locking_data) + (lck->num_share_modes * sizeof(struct share_mode_entry)) + - data->u.s.delete_token_size + + delete_tokens_size + strlen(lck->servicepath) + 1; + lck->stream_name = (const char *)dbuf.dptr + sizeof(struct locking_data) + + (lck->num_share_modes * sizeof(struct share_mode_entry)) + + delete_tokens_size + + strlen(lck->servicepath) + 1 + + strlen(lck->base_name) + 1; + /* * Ensure that each entry has a real process attached. */ @@ -613,7 +726,7 @@ static bool parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) } DEBUG(10,("parse_share_modes: %s\n", str ? str : "")); - if (!process_exists(entry_p->pid)) { + if (!serverid_exists(&entry_p->pid)) { DEBUG(10,("parse_share_modes: deleted %s\n", str ? str : "")); entry_p->op_type = UNUSED_SHARE_MODE_ENTRY; @@ -625,15 +738,17 @@ static bool parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck) return True; } -static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) +static TDB_DATA unparse_share_modes(const 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; + ssize_t sp_len, bn_len, sn_len; + uint32_t delete_tokens_size = 0; + struct delete_token_list *pdtl = NULL; + uint32_t num_delete_token_entries = 0; result.dptr = NULL; result.dsize = 0; @@ -649,15 +764,25 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) } 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); + bn_len = strlen(lck->base_name); + sn_len = lck->stream_name != NULL ? strlen(lck->stream_name) : 0; + + for (pdtl = lck->delete_tokens; pdtl; pdtl = pdtl->next) { + num_delete_token_entries++; + delete_tokens_size += (sizeof(uint32_t) + + sizeof(uint32_t) + + sizeof(uid_t) + + sizeof(gid_t) + + pdtl->delete_token->ngroups*sizeof(gid_t)); + } result.dsize = sizeof(*data) + lck->num_share_modes * sizeof(struct share_mode_entry) + - delete_token_size + + delete_tokens_size + sp_len + 1 + - strlen(lck->filename) + 1; - result.dptr = TALLOC_ARRAY(lck, uint8, result.dsize); + bn_len + 1 + + sn_len + 1; + result.dptr = talloc_array(lck, uint8, result.dsize); if (result.dptr == NULL) { smb_panic("talloc failed"); @@ -666,19 +791,18 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) 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; + data->u.s.num_delete_token_entries = num_delete_token_entries; - 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(), + DEBUG(10,("unparse_share_modes: owrt: %s cwrt: %s, ntok: %u, " + "num: %d\n", + timestring(talloc_tos(), convert_timespec_to_time_t(lck->old_write_time)), - timestring(debug_ctx(), + timestring(talloc_tos(), convert_timespec_to_time_t( lck->changed_write_time)), - (unsigned int)data->u.s.delete_token_size, + (unsigned int)data->u.s.num_delete_token_entries, data->u.s.num_share_mode_entries)); memcpy(result.dptr + sizeof(*data), lck->share_modes, @@ -686,28 +810,46 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck) 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; + /* Store any delete on close tokens. */ + for (pdtl = lck->delete_tokens; pdtl; pdtl = pdtl->next) { + struct security_unix_token *pdt = pdtl->delete_token; + uint32_t token_size = sizeof(uint32_t) + + sizeof(uint32_t) + + sizeof(uid_t) + + sizeof(gid_t) + + (pdt->ngroups * sizeof(gid_t)); + uint8_t *p = result.dptr + offset; - memcpy(p, &lck->delete_token->uid, sizeof(uid_t)); + memcpy(p, &token_size, sizeof(uint32_t)); + p += sizeof(uint32_t); + + memcpy(p, &pdtl->name_hash, sizeof(uint32_t)); + p += sizeof(uint32_t); + + memcpy(p, &pdt->uid, sizeof(uid_t)); p += sizeof(uid_t); - memcpy(p, &lck->delete_token->gid, sizeof(gid_t)); + memcpy(p, &pdt->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)); + for (i = 0; i < pdt->ngroups; i++) { + memcpy(p, &pdt->groups[i], sizeof(gid_t)); p += sizeof(gid_t); } - offset = p - result.dptr; + offset += token_size; } - safe_strcpy((char *)result.dptr + offset, lck->servicepath, - result.dsize - offset - 1); + strlcpy((char *)result.dptr + offset, + lck->servicepath ? lck->servicepath : "", + result.dsize - offset); offset += sp_len + 1; - safe_strcpy((char *)result.dptr + offset, lck->filename, - result.dsize - offset - 1); + strlcpy((char *)result.dptr + offset, + lck->base_name ? lck->base_name : "", + result.dsize - offset); + offset += bn_len + 1; + strlcpy((char *)result.dptr + offset, + lck->stream_name ? lck->stream_name : "", + result.dsize - offset); if (DEBUGLEVEL >= 10) { print_share_mode_table(data); @@ -733,9 +875,18 @@ static int share_mode_lock_destructor(struct share_mode_lock *lck) status = lck->record->delete_rec(lck->record); if (!NT_STATUS_IS_OK(status)) { + char *errmsg; + DEBUG(0, ("delete_rec returned %s\n", nt_errstr(status))); - smb_panic("could not delete share entry"); + + if (asprintf(&errmsg, "could not delete share " + "entry: %s\n", + nt_errstr(status)) == -1) { + smb_panic("could not delete share" + "entry"); + } + smb_panic(errmsg); } } goto done; @@ -743,8 +894,15 @@ static int share_mode_lock_destructor(struct share_mode_lock *lck) status = lck->record->store(lck->record, data, TDB_REPLACE); if (!NT_STATUS_IS_OK(status)) { + char *errmsg; + DEBUG(0, ("store returned %s\n", nt_errstr(status))); - smb_panic("could not store share mode entry"); + + if (asprintf(&errmsg, "could not store share mode entry: %s", + nt_errstr(status)) == -1) { + smb_panic("could not store share mode entry"); + } + smb_panic(errmsg); } done: @@ -755,7 +913,7 @@ static int share_mode_lock_destructor(struct share_mode_lock *lck) static bool fill_share_mode_lock(struct share_mode_lock *lck, struct file_id id, const char *servicepath, - const char *fname, + const struct smb_filename *smb_fname, TDB_DATA share_mode_data, const struct timespec *old_write_time) { @@ -763,12 +921,12 @@ static bool fill_share_mode_lock(struct share_mode_lock *lck, valid even if parse_share_modes fails. */ lck->servicepath = NULL; - lck->filename = NULL; + lck->base_name = NULL; + lck->stream_name = NULL; lck->id = id; lck->num_share_modes = 0; lck->share_modes = NULL; - lck->delete_token = NULL; - lck->delete_on_close = False; + lck->delete_tokens = NULL; ZERO_STRUCT(lck->old_write_time); ZERO_STRUCT(lck->changed_write_time); lck->fresh = False; @@ -777,13 +935,20 @@ static bool fill_share_mode_lock(struct share_mode_lock *lck, lck->fresh = (share_mode_data.dptr == NULL); if (lck->fresh) { - if (fname == NULL || servicepath == NULL + bool has_stream; + if (smb_fname == NULL || servicepath == NULL || old_write_time == NULL) { return False; } - lck->filename = talloc_strdup(lck, fname); + + has_stream = smb_fname->stream_name != NULL; + + lck->base_name = talloc_strdup(lck, smb_fname->base_name); + lck->stream_name = talloc_strdup(lck, smb_fname->stream_name); lck->servicepath = talloc_strdup(lck, servicepath); - if (lck->filename == NULL || lck->servicepath == NULL) { + if (lck->base_name == NULL || + (has_stream && lck->stream_name == NULL) || + lck->servicepath == NULL) { DEBUG(0, ("talloc failed\n")); return False; } @@ -801,7 +966,7 @@ static bool fill_share_mode_lock(struct share_mode_lock *lck, 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 smb_filename *smb_fname, const struct timespec *old_write_time) { struct share_mode_lock *lck; @@ -819,7 +984,7 @@ struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, return NULL; } - if (!fill_share_mode_lock(lck, id, servicepath, fname, + if (!fill_share_mode_lock(lck, id, servicepath, smb_fname, lck->record->value, old_write_time)) { DEBUG(3, ("fill_share_mode_lock failed\n")); TALLOC_FREE(lck); @@ -832,9 +997,7 @@ struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, } struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx, - const struct file_id id, - const char *servicepath, - const char *fname) + const struct file_id id) { struct share_mode_lock *lck; struct file_id tmp; @@ -852,8 +1015,9 @@ struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx, return NULL; } - if (!fill_share_mode_lock(lck, id, servicepath, fname, data, NULL)) { - DEBUG(3, ("fill_share_mode_lock failed\n")); + if (!fill_share_mode_lock(lck, id, NULL, NULL, data, NULL)) { + DEBUG(10, ("fetch_share_mode_unlocked: no share_mode record " + "around (file not open)\n")); TALLOC_FREE(lck); return NULL; } @@ -871,50 +1035,71 @@ struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx, bool rename_share_filename(struct messaging_context *msg_ctx, struct share_mode_lock *lck, const char *servicepath, - const char *newname) + uint32_t orig_name_hash, + uint32_t new_name_hash, + const struct smb_filename *smb_fname_dst) { size_t sp_len; - size_t fn_len; + size_t bn_len; + size_t sn_len; size_t msg_len; char *frm = NULL; int i; + bool strip_two_chars = false; + bool has_stream = smb_fname_dst->stream_name != NULL; DEBUG(10, ("rename_share_filename: servicepath %s newname %s\n", - servicepath, newname)); + servicepath, smb_fname_dst->base_name)); /* * 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; + if (smb_fname_dst->base_name[0] && + smb_fname_dst->base_name[1] && + smb_fname_dst->base_name[0] == '.' && + smb_fname_dst->base_name[1] == '/') { + strip_two_chars = true; } lck->servicepath = talloc_strdup(lck, servicepath); - lck->filename = talloc_strdup(lck, newname); - if (lck->filename == NULL || lck->servicepath == NULL) { + lck->base_name = talloc_strdup(lck, smb_fname_dst->base_name + + (strip_two_chars ? 2 : 0)); + lck->stream_name = talloc_strdup(lck, smb_fname_dst->stream_name); + if (lck->base_name == NULL || + (has_stream && lck->stream_name == 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); + bn_len = strlen(lck->base_name); + sn_len = has_stream ? strlen(lck->stream_name) : 0; - msg_len = MSG_FILE_RENAMED_MIN_SIZE + sp_len + 1 + fn_len + 1; + msg_len = MSG_FILE_RENAMED_MIN_SIZE + sp_len + 1 + bn_len + 1 + + sn_len + 1; /* Set up the name changed message. */ - frm = TALLOC_ARRAY(lck, char, msg_len); + frm = talloc_array(lck, char, msg_len); if (!frm) { return False; } - push_file_id_16(frm, &lck->id); + push_file_id_24(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); + strlcpy(&frm[24], + lck->servicepath ? lck->servicepath : "", + sp_len+1); + strlcpy(&frm[24 + sp_len + 1], + lck->base_name ? lck->base_name : "", + bn_len+1); + strlcpy(&frm[24 + sp_len + 1 + bn_len + 1], + lck->stream_name ? lck->stream_name : "", + sn_len+1); /* Send the messages. */ for (i=0; inum_share_modes; i++) { @@ -922,16 +1107,27 @@ bool rename_share_filename(struct messaging_context *msg_ctx, if (!is_valid_share_mode_entry(se)) { continue; } + + /* If this is a hardlink to the inode + with a different name, skip this. */ + if (se->name_hash != orig_name_hash) { + continue; + } + + se->name_hash = new_name_hash; + /* 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", + DEBUG(10,("rename_share_filename: sending rename message to " + "pid %s file_id %s sharepath %s base_name %s " + "stream_name %s\n", procid_str_static(&se->pid), file_id_string_tos(&lck->id), - lck->servicepath, lck->filename )); + lck->servicepath, lck->base_name, + has_stream ? lck->stream_name : "")); messaging_send_buf(msg_ctx, se->pid, MSG_SMB_FILE_RENAME, (uint8 *)frm, msg_len); @@ -941,6 +1137,7 @@ bool rename_share_filename(struct messaging_context *msg_ctx, } void get_file_infos(struct file_id id, + uint32_t name_hash, bool *delete_on_close, struct timespec *write_time) { @@ -954,12 +1151,12 @@ void get_file_infos(struct file_id id, ZERO_STRUCTP(write_time); } - if (!(lck = fetch_share_mode_unlocked(talloc_tos(), id, NULL, NULL))) { + if (!(lck = fetch_share_mode_unlocked(talloc_tos(), id))) { return; } if (delete_on_close) { - *delete_on_close = lck->delete_on_close; + *delete_on_close = is_delete_on_close_set(lck, name_hash); } if (write_time) { @@ -1012,10 +1209,10 @@ bool is_unused_share_mode_entry(const struct share_mode_entry *e) static void fill_share_mode_entry(struct share_mode_entry *e, files_struct *fsp, - uid_t uid, uint16 mid, uint16 op_type) + uid_t uid, uint64_t mid, uint16 op_type) { ZERO_STRUCTP(e); - e->pid = procid_self(); + e->pid = sconn_server_id(fsp->conn->sconn); e->share_access = fsp->share_access; e->private_options = fsp->fh->private_options; e->access_mask = fsp->access_mask; @@ -1027,14 +1224,17 @@ static void fill_share_mode_entry(struct share_mode_entry *e, e->share_file_id = fsp->fh->gen_id; e->uid = (uint32)uid; e->flags = fsp->posix_open ? SHARE_MODE_FLAG_POSIX_OPEN : 0; + e->name_hash = fsp->name_hash; } static void fill_deferred_open_entry(struct share_mode_entry *e, const struct timeval request_time, - struct file_id id, uint16 mid) + struct file_id id, + struct server_id pid, + uint64_t mid) { ZERO_STRUCTP(e); - e->pid = procid_self(); + e->pid = pid; e->op_mid = mid; e->op_type = DEFERRED_OPEN_ENTRY; e->time.tv_sec = request_time.tv_sec; @@ -1066,22 +1266,19 @@ static void add_share_mode_entry(struct share_mode_lock *lck, } 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) + uid_t uid, uint64_t mid, uint16 op_type) { 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, +void add_deferred_open(struct share_mode_lock *lck, uint64_t mid, struct timeval request_time, - struct file_id id) + struct server_id pid, struct file_id id) { struct share_mode_entry entry; - fill_deferred_open_entry(&entry, request_time, id, mid); + fill_deferred_open_entry(&entry, request_time, id, pid, mid); add_share_mode_entry(lck, &entry); } @@ -1155,12 +1352,13 @@ bool del_share_mode(struct share_mode_lock *lck, files_struct *fsp) return True; } -void del_deferred_open_entry(struct share_mode_lock *lck, uint16 mid) +void del_deferred_open_entry(struct share_mode_lock *lck, uint64_t mid, + struct server_id pid) { struct share_mode_entry entry, *e; fill_deferred_open_entry(&entry, timeval_zero(), - lck->id, mid); + lck->id, pid, mid); e = find_share_mode_entry(lck, &entry); if (e == NULL) { @@ -1187,8 +1385,19 @@ bool remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp) return False; } - e->op_mid = 0; - e->op_type = NO_OPLOCK; + if (EXCLUSIVE_OPLOCK_TYPE(e->op_type)) { + /* + * Going from exclusive or batch, + * we always go through FAKE_LEVEL_II + * first. + */ + if (!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) { + smb_panic("remove_share_oplock: logic error"); + } + e->op_type = FAKE_LEVEL_II_OPLOCK; + } else { + e->op_type = NO_OPLOCK; + } lck->modified = True; return True; } @@ -1215,27 +1424,20 @@ bool downgrade_share_oplock(struct share_mode_lock *lck, files_struct *fsp) } /**************************************************************************** - 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. + Check if setting delete on close is allowed on this fsp. ****************************************************************************/ -NTSTATUS can_set_delete_on_close(files_struct *fsp, bool delete_on_close, - uint32 dosmode) +NTSTATUS can_set_delete_on_close(files_struct *fsp, uint32 dosmode) { - if (!delete_on_close) { - return NT_STATUS_OK; - } - /* * Only allow delete on close for writable files. */ - if ((dosmode & aRONLY) && + if ((dosmode & FILE_ATTRIBUTE_READONLY) && !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 )); + fsp_str_dbg(fsp))); return NT_STATUS_CANNOT_DELETE; } @@ -1246,7 +1448,7 @@ NTSTATUS can_set_delete_on_close(files_struct *fsp, bool delete_on_close, 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 )); + fsp_str_dbg(fsp))); return NT_STATUS_ACCESS_DENIED; } @@ -1258,48 +1460,30 @@ NTSTATUS can_set_delete_on_close(files_struct *fsp, bool delete_on_close, 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 )); + fsp_str_dbg(fsp))); 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); + SMB_ASSERT(!is_ntfs_stream_smb_fname(fsp->fsp_name)); + return can_delete_directory(fsp->conn, + fsp->fsp_name->base_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; inum_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. + Return a talloced copy of a struct security_unix_token. NULL on fail. (Should this be in locking.c.... ?). *************************************************************************/ -static UNIX_USER_TOKEN *copy_unix_token(TALLOC_CTX *ctx, UNIX_USER_TOKEN *tok) +static struct security_unix_token *copy_unix_token(TALLOC_CTX *ctx, const struct security_unix_token *tok) { - UNIX_USER_TOKEN *cpy; + struct security_unix_token *cpy; - if (tok == NULL) { - return NULL; - } - - cpy = TALLOC_P(ctx, UNIX_USER_TOKEN); + cpy = TALLOC_P(ctx, struct security_unix_token); if (!cpy) { return NULL; } @@ -1309,26 +1493,40 @@ static UNIX_USER_TOKEN *copy_unix_token(TALLOC_CTX *ctx, UNIX_USER_TOKEN *tok) cpy->ngroups = tok->ngroups; if (tok->ngroups) { /* Make this a talloc child of cpy. */ - cpy->groups = TALLOC_ARRAY(cpy, gid_t, tok->ngroups); + cpy->groups = (gid_t *)talloc_memdup( + cpy, tok->groups, tok->ngroups * sizeof(gid_t)); if (!cpy->groups) { + TALLOC_FREE(cpy); return NULL; } - memcpy(cpy->groups, tok->groups, tok->ngroups * sizeof(gid_t)); } return cpy; } /**************************************************************************** - Replace the delete on close token. + Adds a delete on close token. ****************************************************************************/ -void set_delete_on_close_token(struct share_mode_lock *lck, UNIX_USER_TOKEN *tok) +static bool add_delete_on_close_token(struct share_mode_lock *lck, + uint32_t name_hash, + const struct security_unix_token *tok) { - TALLOC_FREE(lck->delete_token); /* Also deletes groups... */ + struct delete_token_list *dtl; - /* Copy the new token (can be NULL). */ - lck->delete_token = copy_unix_token(lck, tok); - lck->modified = True; + dtl = TALLOC_ZERO_P(lck, struct delete_token_list); + if (dtl == NULL) { + return false; + } + + dtl->name_hash = name_hash; + dtl->delete_token = copy_unix_token(lck, tok); + if (dtl->delete_token == NULL) { + TALLOC_FREE(dtl); + return false; + } + DLIST_ADD(lck->delete_tokens, dtl); + lck->modified = true; + return true; } /**************************************************************************** @@ -1338,30 +1536,58 @@ void set_delete_on_close_token(struct share_mode_lock *lck, UNIX_USER_TOKEN *tok 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 + This makes a copy of any struct security_unix_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) +void set_delete_on_close_lck(files_struct *fsp, + struct share_mode_lock *lck, + bool delete_on_close, + const struct security_unix_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); + struct delete_token_list *dtl; + bool ret; + + if (delete_on_close) { + SMB_ASSERT(tok != NULL); + } else { + SMB_ASSERT(tok == NULL); + } + + for (dtl = lck->delete_tokens; dtl; dtl = dtl->next) { + if (dtl->name_hash == fsp->name_hash) { + lck->modified = true; + if (delete_on_close == false) { + /* Delete this entry. */ + DLIST_REMOVE(lck->delete_tokens, dtl); + TALLOC_FREE(dtl); + return; + } + /* Replace this token with the + given tok. */ + TALLOC_FREE(dtl->delete_token); + dtl->delete_token = copy_unix_token(dtl, tok); + SMB_ASSERT(dtl->delete_token != NULL); } - lck->modified = True; } + + if (!delete_on_close) { + /* Nothing to delete - not found. */ + return; + } + + ret = add_delete_on_close_token(lck, fsp->name_hash, tok); + SMB_ASSERT(ret); } -bool set_delete_on_close(files_struct *fsp, bool delete_on_close, UNIX_USER_TOKEN *tok) +bool set_delete_on_close(files_struct *fsp, bool delete_on_close, const struct security_unix_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 )); + fsp_str_dbg(fsp))); lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, NULL); @@ -1369,65 +1595,91 @@ bool set_delete_on_close(files_struct *fsp, bool delete_on_close, UNIX_USER_TOKE return False; } - set_delete_on_close_lck(lck, delete_on_close, tok); + set_delete_on_close_lck(fsp, lck, delete_on_close, + delete_on_close ? tok : NULL); if (fsp->is_directory) { - send_stat_cache_delete_message(fsp->fsp_name); + SMB_ASSERT(!is_ntfs_stream_smb_fname(fsp->fsp_name)); + send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx, + fsp->fsp_name->base_name); } TALLOC_FREE(lck); + + fsp->delete_on_close = delete_on_close; + return True; } -/**************************************************************************** - Sets the allow initial delete on close flag for this share mode. -****************************************************************************/ +const struct security_unix_token *get_delete_on_close_token(struct share_mode_lock *lck, uint32_t name_hash) +{ + struct delete_token_list *dtl; + + DEBUG(10,("get_delete_on_close_token: name_hash = 0x%x\n", + (unsigned int)name_hash )); -bool set_allow_initial_delete_on_close(struct share_mode_lock *lck, files_struct *fsp, bool delete_on_close) + for (dtl = lck->delete_tokens; dtl; dtl = dtl->next) { + DEBUG(10,("get_delete_on_close_token: dtl->name_hash = 0x%x\n", + (unsigned int)dtl->name_hash )); + if (dtl->name_hash == name_hash) { + return dtl->delete_token; + } + } + return NULL; +} + +bool is_delete_on_close_set(struct share_mode_lock *lck, uint32_t name_hash) { - struct share_mode_entry entry, *e; + return (get_delete_on_close_token(lck, name_hash) != NULL); +} - /* 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); +bool set_sticky_write_time(struct file_id fileid, struct timespec write_time) +{ + struct share_mode_lock *lck; - e = find_share_mode_entry(lck, &entry); - if (e == NULL) { + DEBUG(5,("set_sticky_write_time: %s id=%s\n", + timestring(talloc_tos(), + convert_timespec_to_time_t(write_time)), + file_id_string_tos(&fileid))); + + lck = get_share_mode_lock(NULL, fileid, NULL, NULL, NULL); + if (lck == 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; + if (timespec_compare(&lck->changed_write_time, &write_time) != 0) { + lck->modified = True; + lck->changed_write_time = write_time; } - lck->modified = True; + + TALLOC_FREE(lck); return True; } -bool set_write_time(struct file_id fileid, struct timespec write_time, - bool overwrite) +bool set_write_time(struct file_id fileid, struct timespec write_time) { struct share_mode_lock *lck; - DEBUG(5,("set_write_time: %s overwrite=%d id=%s\n", - timestring(debug_ctx(), + DEBUG(5,("set_write_time: %s id=%s\n", + timestring(talloc_tos(), convert_timespec_to_time_t(write_time)), - overwrite, file_id_string_tos(&fileid))); + 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)) { + if (timespec_compare(&lck->old_write_time, &write_time) != 0) { lck->modified = True; - lck->changed_write_time = write_time; + lck->old_write_time = write_time; } TALLOC_FREE(lck); return True; } + struct forall_state { void (*fn)(const struct share_mode_entry *entry, const char *sharepath, @@ -1443,6 +1695,8 @@ static int traverse_fn(struct db_record *rec, void *_state) struct share_mode_entry *shares; const char *sharepath; const char *fname; + const char *del_tokens; + uint32_t total_del_token_size = 0; int i; /* Ensure this is a locking_key record. */ @@ -1451,12 +1705,22 @@ static int traverse_fn(struct db_record *rec, void *_state) data = (struct locking_data *)rec->value.dptr; shares = (struct share_mode_entry *)(rec->value.dptr + sizeof(*data)); + del_tokens = (const char *)rec->value.dptr + sizeof(*data) + + data->u.s.num_share_mode_entries*sizeof(*shares); + + for (i = 0; i < data->u.s.num_delete_token_entries; i++) { + uint32_t del_token_size; + memcpy(&del_token_size, del_tokens, sizeof(uint32_t)); + total_del_token_size += del_token_size; + del_tokens += del_token_size; + } + sharepath = (const char *)rec->value.dptr + sizeof(*data) + data->u.s.num_share_mode_entries*sizeof(*shares) + - data->u.s.delete_token_size; + total_del_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 + + total_del_token_size + strlen(sharepath) + 1; for (i=0;iu.s.num_share_mode_entries;i++) {