smbd: Use share_mode_forall_entries() in vfs_default_durable_reconnect()
[metze/samba/wip.git] / source3 / smbd / durable.c
index c1e0c869822e586f46cafdd4cf2debdc54fa266b..c71a948191a0f73a814fab3c72d8972b6adcd9dd 100644 (file)
@@ -496,6 +496,22 @@ static bool vfs_default_durable_reconnect_check_stat(
        return true;
 }
 
+static bool durable_reconnect_fn(
+       struct share_mode_entry *e,
+       bool *modified,
+       void *private_data)
+{
+       struct share_mode_entry *dst_e = private_data;
+
+       if (dst_e->pid.pid != 0) {
+               DBG_INFO("Found more than one entry, invalidating previous\n");
+               dst_e->pid.pid = 0;
+               return true;    /* end the loop through share mode entries */
+       }
+       *dst_e = *e;
+       return false;           /* Look at potential other entries */
+}
+
 NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                                       struct smb_request *smb1req,
                                       struct smbXsrv_open *op,
@@ -505,7 +521,7 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                                       DATA_BLOB *new_cookie)
 {
        struct share_mode_lock *lck;
-       struct share_mode_entry *e;
+       struct share_mode_entry e;
        struct files_struct *fsp = NULL;
        NTSTATUS status;
        bool ok;
@@ -596,27 +612,22 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       if (lck->data->num_share_modes == 0) {
-               DEBUG(1, ("vfs_default_durable_reconnect: Error: no share-mode "
-                         "entry in existing share mode lock\n"));
+       e = (struct share_mode_entry) { .pid.pid = 0 };
+
+       ok = share_mode_forall_entries(lck, durable_reconnect_fn, &e);
+       if (!ok) {
+               DBG_WARNING("share_mode_forall_entries failed\n");
                TALLOC_FREE(lck);
                return NT_STATUS_INTERNAL_DB_ERROR;
        }
 
-       if (lck->data->num_share_modes > 1) {
-               /*
-                * It can't be durable if there is more than one handle
-                * on the file.
-                */
-               DEBUG(5, ("vfs_default_durable_reconnect: more than one "
-                         "share-mode entry - can not be durable\n"));
+       if (e.pid.pid == 0) {
+               DBG_WARNING("Did not find a unique valid share mode entry\n");
                TALLOC_FREE(lck);
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       e = &lck->data->share_modes[0];
-
-       if (!server_id_is_disconnected(&e->pid)) {
+       if (!server_id_is_disconnected(&e.pid)) {
                DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
                          "reconnect for handle that was not marked "
                          "disconnected (e.g. smbd or cluster node died)\n"));
@@ -624,17 +635,17 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       if (e->share_file_id != op->global->open_persistent_id) {
+       if (e.share_file_id != op->global->open_persistent_id) {
                DBG_INFO("denying durable "
                         "share_file_id changed %"PRIu64" != %"PRIu64" "
                         "(e.g. another client had opened the file)\n",
-                        e->share_file_id,
+                        e.share_file_id,
                         op->global->open_persistent_id);
                TALLOC_FREE(lck);
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       if ((e->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
+       if ((e.access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
            !CAN_WRITE(conn))
        {
                DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
@@ -656,12 +667,12 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                return status;
        }
 
-       fsp->fh->private_options = e->private_options;
+       fsp->fh->private_options = e.private_options;
        fsp->file_id = file_id;
        fsp->file_pid = smb1req->smbpid;
        fsp->vuid = smb1req->vuid;
-       fsp->open_time = e->time;
-       fsp->access_mask = e->access_mask;
+       fsp->open_time = e.time;
+       fsp->access_mask = e.access_mask;
        fsp->can_read = ((fsp->access_mask & (FILE_READ_DATA)) != 0);
        fsp->can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
        fsp->fnum = op->local_id;
@@ -684,7 +695,7 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
         * We do not support aio write behind for smb2
         */
        fsp->aio_write_behind = false;
-       fsp->oplock_type = e->op_type;
+       fsp->oplock_type = e.op_type;
 
        if (fsp->oplock_type == LEASE_OPLOCK) {
                uint32_t current_state;
@@ -695,15 +706,15 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                 * stored one in the share_mode_entry.
                 */
                if (!GUID_equal(fsp_client_guid(fsp),
-                               &e->client_guid)) {
+                               &e.client_guid)) {
                        TALLOC_FREE(lck);
                        fsp_free(fsp);
                        return NT_STATUS_OBJECT_NAME_NOT_FOUND;
                }
 
                status = leases_db_get(
-                       &e->client_guid,
-                       &e->lease_key,
+                       &e.client_guid,
+                       &e.lease_key,
                        &file_id,
                        &current_state, /* current_state */
                        NULL, /* breaking */
@@ -719,7 +730,7 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
 
                fsp->lease = find_fsp_lease(
                        fsp,
-                       &e->lease_key,
+                       &e.lease_key,
                        current_state,
                        lease_version,
                        epoch);
@@ -750,9 +761,20 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
        op->compat = fsp;
        fsp->op = op;
 
-       e->pid = messaging_server_id(conn->sconn->msg_ctx);
-       e->op_mid = smb1req->mid;
-       e->share_file_id = fsp->fh->gen_id;
+       ok = reset_share_mode_entry(
+               lck,
+               e.pid,
+               e.share_file_id,
+               messaging_server_id(conn->sconn->msg_ctx),
+               smb1req->mid,
+               fsp->fh->gen_id);
+       if (!ok) {
+               DBG_DEBUG("Could not set new share_mode_entry values\n");
+               TALLOC_FREE(lck);
+               op->compat = NULL;
+               fsp_free(fsp);
+               return NT_STATUS_INTERNAL_ERROR;
+       }
 
        ok = brl_reconnect_disconnected(fsp);
        if (!ok) {