smbd: Simplify find_share_mode_entry callers
[mat/samba.git] / source3 / locking / locking.c
index cc921527272b9708c2801cfa370a9e0712d7ea4e..d7ba65395d03d03a640b06ae946273b98f0374c2 100644 (file)
@@ -154,11 +154,11 @@ bool strict_lock_default(files_struct *fsp, struct lock_struct *plock)
        }
 
        DEBUG(10,("strict_lock_default: flavour = %s brl start=%.0f "
-                       "len=%.0f %s for fnum %d file %s\n",
+                       "len=%.0f %s for fnum %llu file %s\n",
                        lock_flav_name(plock->lock_flav),
                        (double)plock->start, (double)plock->size,
                        ret ? "unlocked" : "locked",
-                       plock->fnum, fsp_str_dbg(fsp)));
+                       (unsigned long long)plock->fnum, fsp_str_dbg(fsp)));
 
        return ret;
 }
@@ -267,10 +267,10 @@ 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 "
-               "blocking_lock=%s requested for fnum %d file %s\n",
+               "blocking_lock=%s requested for %s file %s\n",
                lock_flav_name(lock_flav), lock_type_name(lock_type),
                (double)offset, (double)count, blocking_lock ? "true" :
-               "false", fsp->fnum, fsp_str_dbg(fsp)));
+               "false", fsp_fnum_dbg(fsp), fsp_str_dbg(fsp)));
 
        br_lck = brl_get_locks(talloc_tos(), fsp);
        if (!br_lck) {
@@ -318,8 +318,8 @@ NTSTATUS do_unlock(struct messaging_context *msg_ctx,
                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,
+       DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for %s file %s\n",
+                 (double)offset, (double)count, fsp_fnum_dbg(fsp),
                  fsp_str_dbg(fsp)));
 
        br_lck = brl_get_locks(talloc_tos(), fsp);
@@ -369,8 +369,8 @@ NTSTATUS do_lock_cancel(files_struct *fsp,
                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,
+       DEBUG(10,("do_lock_cancel: cancel start=%.0f len=%.0f requested for %s file %s\n",
+                 (double)offset, (double)count, fsp_fnum_dbg(fsp),
                  fsp_str_dbg(fsp)));
 
        br_lck = brl_get_locks(talloc_tos(), fsp);
@@ -411,7 +411,7 @@ void locking_close_file(struct messaging_context *msg_ctx,
                return;
        }
 
-       /* If we have not outstanding locks or pending
+       /* If we have no outstanding locks or pending
         * locks then we don't need to look in the lock db.
         */
 
@@ -482,6 +482,7 @@ bool rename_share_filename(struct messaging_context *msg_ctx,
        int i;
        bool strip_two_chars = false;
        bool has_stream = smb_fname_dst->stream_name != NULL;
+       struct server_id self_pid = messaging_server_id(msg_ctx);
 
        DEBUG(10, ("rename_share_filename: servicepath %s newname %s\n",
                   servicepath, smb_fname_dst->base_name));
@@ -552,7 +553,11 @@ bool rename_share_filename(struct messaging_context *msg_ctx,
                se->name_hash = new_name_hash;
 
                /* But not to ourselves... */
-               if (procid_is_me(&se->pid)) {
+               if (serverid_equal(&se->pid, &self_pid)) {
+                       continue;
+               }
+
+               if (share_mode_stale_pid(d, i)) {
                        continue;
                }
 
@@ -612,17 +617,80 @@ bool is_valid_share_mode_entry(const struct share_mode_entry *e)
 {
        int num_props = 0;
 
+       if (e->stale) {
+               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);
+       if ((num_props > 1) && serverid_exists(&e->pid)) {
+               smb_panic("Invalid share mode entry");
+       }
        return (num_props != 0);
 }
 
-bool is_deferred_open_entry(const struct share_mode_entry *e)
+/*
+ * In case d->share_modes[i] conflicts with something or otherwise is
+ * being used, we need to make sure the corresponding process still
+ * exists.
+ */
+bool share_mode_stale_pid(struct share_mode_data *d, uint32_t idx)
 {
-       return (e->op_type == DEFERRED_OPEN_ENTRY);
+       struct share_mode_entry *e;
+
+       if (idx > d->num_share_modes) {
+               DEBUG(1, ("Asking for index %u, only %u around\n",
+                         idx, (unsigned)d->num_share_modes));
+               return false;
+       }
+       e = &d->share_modes[idx];
+       if (e->stale) {
+               /*
+                * Checked before
+                */
+               return true;
+       }
+       if (serverid_exists(&e->pid)) {
+               DEBUG(10, ("PID %s (index %u out of %u) still exists\n",
+                          procid_str_static(&e->pid), idx,
+                          (unsigned)d->num_share_modes));
+               return false;
+       }
+       DEBUG(10, ("PID %s (index %u out of %u) does not exist anymore\n",
+                  procid_str_static(&e->pid), idx,
+                  (unsigned)d->num_share_modes));
+
+       e->stale = true;
+
+       if (d->num_delete_tokens != 0) {
+               uint32_t i, num_stale;
+
+               /*
+                * We cannot have any delete tokens
+                * if there are no valid share modes.
+                */
+
+               num_stale = 0;
+
+               for (i=0; i<d->num_share_modes; i++) {
+                       if (d->share_modes[i].stale) {
+                               num_stale += 1;
+                       }
+               }
+
+               if (num_stale == d->num_share_modes) {
+                       /*
+                        * No non-stale share mode found
+                        */
+                       TALLOC_FREE(d->delete_tokens);
+                       d->num_delete_tokens = 0;
+               }
+       }
+
+       d->modified = true;
+       return true;
 }
 
 /*******************************************************************
@@ -649,92 +717,56 @@ static void fill_share_mode_entry(struct share_mode_entry *e,
        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,
-                                    struct server_id pid,
-                                    uint64_t mid)
-{
-       ZERO_STRUCTP(e);
-       e->pid = pid;
-       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_data *d,
+static bool add_share_mode_entry(struct share_mode_data *d,
                                 const struct share_mode_entry *entry)
 {
-       ADD_TO_ARRAY(d, struct share_mode_entry, *entry,
-                    &d->share_modes, &d->num_share_modes);
-       d->modified = True;
+       struct share_mode_entry *tmp;
+
+       tmp = talloc_realloc(d, d->share_modes, struct share_mode_entry,
+                            d->num_share_modes+1);
+       if (tmp == NULL) {
+               return false;
+       }
+       d->share_modes = tmp;
+       d->share_modes[d->num_share_modes] = *entry;
+       d->num_share_modes += 1;
+       d->modified = true;
+       return true;
 }
 
-void set_share_mode(struct share_mode_lock *lck, files_struct *fsp,
+bool set_share_mode(struct share_mode_lock *lck, files_struct *fsp,
                    uid_t uid, uint64_t mid, uint16 op_type)
 {
        struct share_mode_entry entry;
        fill_share_mode_entry(&entry, fsp, uid, mid, op_type);
-       add_share_mode_entry(lck->data, &entry);
+       return add_share_mode_entry(lck->data, &entry);
 }
 
-void add_deferred_open(struct share_mode_lock *lck, uint64_t mid,
-                      struct timeval request_time,
-                      struct server_id pid, struct file_id id)
-{
-       struct share_mode_entry entry;
-       fill_deferred_open_entry(&entry, request_time, id, pid, mid);
-       add_share_mode_entry(lck->data, &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_data *d,
-                                                     struct share_mode_entry *entry)
+static struct share_mode_entry *find_share_mode_entry(
+       struct share_mode_lock *lck, files_struct *fsp)
 {
+       struct share_mode_data *d = lck->data;
+       struct server_id pid;
        int i;
 
+       pid = messaging_server_id(fsp->conn->sconn->msg_ctx);
+
        for (i=0; i<d->num_share_modes; i++) {
                struct share_mode_entry *e = &d->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_valid_share_mode_entry(e)) {
+                       continue;
                }
-               if (is_deferred_open_entry(entry) &&
-                   is_deferred_open_entry(e) &&
-                   deferred_open_identical(e, entry)) {
-                       return e;
+               if (!serverid_equal(&pid, &e->pid)) {
+                       continue;
+               }
+               if (!file_id_equal(&fsp->file_id, &e->id)) {
+                       continue;
+               }
+               if (fsp->fh->gen_id != e->share_file_id) {
+                       continue;
                }
+               return e;
        }
        return NULL;
 }
@@ -746,12 +778,9 @@ static struct share_mode_entry *find_share_mode_entry(struct share_mode_data *d,
 
 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);
+       struct share_mode_entry *e;
 
-       e = find_share_mode_entry(lck->data, &entry);
+       e = find_share_mode_entry(lck, fsp);
        if (e == NULL) {
                return False;
        }
@@ -761,21 +790,39 @@ bool del_share_mode(struct share_mode_lock *lck, files_struct *fsp)
        return True;
 }
 
-void del_deferred_open_entry(struct share_mode_lock *lck, uint64_t mid,
-                            struct server_id pid)
+bool mark_share_mode_disconnected(struct share_mode_lock *lck,
+                                 struct files_struct *fsp)
 {
-       struct share_mode_entry entry, *e;
+       struct share_mode_entry *e;
 
-       fill_deferred_open_entry(&entry, timeval_zero(),
-                                lck->data->id, pid, mid);
+       if (lck->data->num_share_modes != 1) {
+               return false;
+       }
 
-       e = find_share_mode_entry(lck->data, &entry);
+       if (fsp->op == NULL) {
+               return false;
+       }
+       if (!fsp->op->global->durable) {
+               return false;
+       }
+
+       e = find_share_mode_entry(lck, fsp);
        if (e == NULL) {
-               return;
+               return false;
        }
-       *e = lck->data->share_modes[lck->data->num_share_modes-1];
-       lck->data->num_share_modes -= 1;
-       lck->data->modified = True;
+
+       DEBUG(10, ("Marking share mode entry disconnected for durable handle\n"));
+
+       server_id_set_disconnected(&e->pid);
+
+       /*
+        * On reopen the caller needs to check that
+        * the client comes with the correct handle.
+        */
+       e->share_file_id = fsp->op->global->open_persistent_id;
+
+       lck->data->modified = true;
+       return true;
 }
 
 /*******************************************************************
@@ -784,12 +831,9 @@ void del_deferred_open_entry(struct share_mode_lock *lck, uint64_t mid,
 
 bool remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp)
 {
-       struct share_mode_entry entry, *e;
+       struct share_mode_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->data, &entry);
+       e = find_share_mode_entry(lck, fsp);
        if (e == NULL) {
                return False;
        }
@@ -817,12 +861,9 @@ bool remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp)
 
 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);
+       struct share_mode_entry *e;
 
-       e = find_share_mode_entry(lck->data, &entry);
+       e = find_share_mode_entry(lck, fsp);
        if (e == NULL) {
                return False;
        }
@@ -832,35 +873,6 @@ bool downgrade_share_oplock(struct share_mode_lock *lck, files_struct *fsp)
        return True;
 }
 
-/*************************************************************************
- Return a talloced copy of a struct security_unix_token. NULL on fail.
- (Should this be in locking.c.... ?).
-*************************************************************************/
-
-static struct security_unix_token *copy_unix_token(TALLOC_CTX *ctx, const struct security_unix_token *tok)
-{
-       struct security_unix_token *cpy;
-
-       cpy = talloc(ctx, struct security_unix_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 = (gid_t *)talloc_memdup(
-                       cpy, tok->groups, tok->ngroups * sizeof(gid_t));
-               if (!cpy->groups) {
-                       TALLOC_FREE(cpy);
-                       return NULL;
-               }
-       }
-       return cpy;
-}
-
 /****************************************************************************
  Adds a delete on close token.
 ****************************************************************************/
@@ -934,16 +946,17 @@ void set_delete_on_close_lck(files_struct *fsp,
                                *dt = d->delete_tokens[
                                        d->num_delete_tokens-1];
                                d->num_delete_tokens -= 1;
-                               return;
+                       } else {
+                               /* Replace this token with the
+                                  given tok. */
+                               TALLOC_FREE(dt->delete_nt_token);
+                               dt->delete_nt_token = dup_nt_token(dt, nt_tok);
+                               SMB_ASSERT(dt->delete_nt_token != NULL);
+                               TALLOC_FREE(dt->delete_token);
+                               dt->delete_token = copy_unix_token(dt, tok);
+                               SMB_ASSERT(dt->delete_token != NULL);
                        }
-                       /* Replace this token with the
-                          given tok. */
-                       TALLOC_FREE(dt->delete_nt_token);
-                       dt->delete_nt_token = dup_nt_token(dt, nt_tok);
-                       SMB_ASSERT(dt->delete_nt_token != NULL);
-                       TALLOC_FREE(dt->delete_token);
-                       dt->delete_token = copy_unix_token(dt, tok);
-                       SMB_ASSERT(dt->delete_token != NULL);
+                       return;
                }
        }
 
@@ -963,8 +976,8 @@ 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,
+                 "%s, file %s\n",
+                 delete_on_close ? "Adding" : "Removing", fsp_fnum_dbg(fsp),
                  fsp_str_dbg(fsp)));
 
        lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
@@ -995,6 +1008,26 @@ bool set_delete_on_close(files_struct *fsp, bool delete_on_close,
        return True;
 }
 
+static struct delete_token *find_delete_on_close_token(
+       struct share_mode_data *d, uint32_t name_hash)
+{
+       uint32_t i;
+
+       DEBUG(10, ("find_delete_on_close_token: name_hash = 0x%x\n",
+                  (unsigned int)name_hash));
+
+       for (i=0; i<d->num_delete_tokens; i++) {
+               struct delete_token *dt = &d->delete_tokens[i];
+
+               DEBUG(10, ("find__delete_on_close_token: dt->name_hash = 0x%x\n",
+                          (unsigned int)dt->name_hash ));
+               if (dt->name_hash == name_hash) {
+                       return dt;
+               }
+       }
+       return NULL;
+}
+
 /****************************************************************************
  Return the NT token and UNIX token if there's a match. Return true if
  found, false if not.
@@ -1005,31 +1038,20 @@ bool get_delete_on_close_token(struct share_mode_lock *lck,
                                        const struct security_token **pp_nt_tok,
                                        const struct security_unix_token **pp_tok)
 {
-       int i;
+       struct delete_token *dt;
 
-       DEBUG(10,("get_delete_on_close_token: name_hash = 0x%x\n",
-                       (unsigned int)name_hash ));
-
-       for (i=0; i<lck->data->num_delete_tokens; i++) {
-               struct delete_token *dt = &lck->data->delete_tokens[i];
-               DEBUG(10,("get_delete_on_close_token: dtl->name_hash = 0x%x\n",
-                               (unsigned int)dt->name_hash ));
-               if (dt->name_hash == name_hash) {
-                       if (pp_nt_tok) {
-                               *pp_nt_tok = dt->delete_nt_token;
-                       }
-                       if (pp_tok) {
-                               *pp_tok =  dt->delete_token;
-                       }
-                       return true;
-               }
+       dt = find_delete_on_close_token(lck->data, name_hash);
+       if (dt == NULL) {
+               return false;
        }
-       return false;
+       *pp_nt_tok = dt->delete_nt_token;
+       *pp_tok =  dt->delete_token;
+       return true;
 }
 
 bool is_delete_on_close_set(struct share_mode_lock *lck, uint32_t name_hash)
 {
-       return get_delete_on_close_token(lck, name_hash, NULL, NULL);
+       return find_delete_on_close_token(lck->data, name_hash) != NULL;
 }
 
 bool set_sticky_write_time(struct file_id fileid, struct timespec write_time)