try to fix SMB_ASSERT(got_token)... TODO
[metze/samba/wip.git] / source3 / smbd / close.c
index 1a123b49c8ac21ae70926873e6285285eaac5eb4..bdd177cca8f38eb43347cf9ed48eb437f85138da 100644 (file)
@@ -118,7 +118,7 @@ static NTSTATUS check_magic(struct files_struct *fsp)
                goto out;
        }
 
-       if (transfer_file(tmp_fd,outfd,(SMB_OFF_T)st.st_ex_size) == (SMB_OFF_T)-1) {
+       if (transfer_file(tmp_fd,outfd,(off_t)st.st_ex_size) == (off_t)-1) {
                int err = errno;
                close(tmp_fd);
                close(outfd);
@@ -158,8 +158,8 @@ static NTSTATUS close_filestruct(files_struct *fsp)
 
 static int compare_share_mode_times(const void *p1, const void *p2)
 {
-       struct share_mode_entry *s1 = (struct share_mode_entry *)p1;
-       struct share_mode_entry *s2 = (struct share_mode_entry *)p2;
+       const struct share_mode_entry *s1 = (const struct share_mode_entry *)p1;
+       const struct share_mode_entry *s2 = (const struct share_mode_entry *)p2;
        return timeval_compare(&s1->time, &s2->time);
 }
 
@@ -173,15 +173,21 @@ static void notify_deferred_opens(struct smbd_server_connection *sconn,
        uint32_t i, num_deferred;
        struct share_mode_entry *deferred;
 
-       if (!should_notify_deferred_opens()) {
+       if (!should_notify_deferred_opens(sconn)) {
                return;
        }
 
        num_deferred = 0;
        for (i=0; i<lck->data->num_share_modes; i++) {
-               if (is_deferred_open_entry(&lck->data->share_modes[i])) {
-                       num_deferred += 1;
+               struct share_mode_entry *e = &lck->data->share_modes[i];
+
+               if (!is_deferred_open_entry(e)) {
+                       continue;
                }
+               if (share_mode_stale_pid(lck->data, i)) {
+                       continue;
+               }
+               num_deferred += 1;
        }
        if (num_deferred == 0) {
                return;
@@ -332,6 +338,8 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
        NTSTATUS tmp_status;
        struct file_id id;
        const struct security_unix_token *del_token = NULL;
+       const struct security_token *del_nt_token = NULL;
+       bool got_tokens = false;
 
        /* Ensure any pending write time updates are done. */
        if (fsp->update_write_time_event) {
@@ -377,12 +385,6 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
                }
        }
 
-       if (!del_share_mode(lck, fsp)) {
-               DEBUG(0, ("close_remove_share_mode: Could not delete share "
-                         "entry for file %s\n",
-                         fsp_str_dbg(fsp)));
-       }
-
        if (fsp->initial_delete_on_close &&
                        !is_delete_on_close_set(lck, fsp->name_hash)) {
                bool became_user = False;
@@ -395,7 +397,9 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
                        became_user = True;
                }
                fsp->delete_on_close = true;
-               set_delete_on_close_lck(fsp, lck, True, get_current_utok(conn));
+               set_delete_on_close_lck(fsp, lck, True,
+                               get_current_nttok(conn),
+                               get_current_utok(conn));
                if (became_user) {
                        unbecome_user();
                }
@@ -410,11 +414,17 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
                   POSIX delete now. */
                for (i=0; i<lck->data->num_share_modes; i++) {
                        struct share_mode_entry *e = &lck->data->share_modes[i];
+
+                       //TODO: continue if our own entry...
+
                        if (is_valid_share_mode_entry(e) &&
                                        e->name_hash == fsp->name_hash) {
                                if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
                                        continue;
                                }
+                               if (share_mode_stale_pid(lck->data, i)) {
+                                       continue;
+                               }
                                delete_file = False;
                                break;
                        }
@@ -432,6 +442,12 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
 
        if (!(close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) ||
                        !delete_file) {
+               if (!del_share_mode(lck, fsp)) {
+                       DEBUG(0, ("close_remove_share_mode: Could not delete share "
+                                 "entry for file %s\n",
+                                 fsp_str_dbg(fsp)));
+               }
+
                TALLOC_FREE(lck);
                return NT_STATUS_OK;
        }
@@ -448,8 +464,9 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
         */
        fsp->update_write_time_on_close = false;
 
-       del_token = get_delete_on_close_token(lck, fsp->name_hash);
-       SMB_ASSERT(del_token != NULL);
+       got_tokens = get_delete_on_close_token(lck, fsp->name_hash,
+                                       &del_nt_token, &del_token);
+       SMB_ASSERT(got_tokens);
 
        if (!unix_token_equal(del_token, get_current_utok(conn))) {
                /* Become the user who requested the delete. */
@@ -468,7 +485,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
                            del_token->gid,
                            del_token->ngroups,
                            del_token->groups,
-                           NULL);
+                           del_nt_token);
 
                changed_user = true;
        }
@@ -541,7 +558,7 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
         */
 
        fsp->delete_on_close = false;
-       set_delete_on_close_lck(fsp, lck, false, NULL);
+       set_delete_on_close_lck(fsp, lck, false, NULL, NULL);
 
  done:
 
@@ -550,6 +567,14 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
                pop_sec_ctx();
        }
 
+       if (delete_file) {
+               if (!del_share_mode(lck, fsp)) {
+                       DEBUG(0, ("close_remove_share_mode: Could not delete share "
+                                 "entry for file %s\n",
+                                 fsp_str_dbg(fsp)));
+               }
+       }
+
        TALLOC_FREE(lck);
 
        if (delete_file) {
@@ -611,12 +636,24 @@ static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
                return NT_STATUS_OK;
        }
 
-       /* On close if we're changing the real file time we
-        * must update it in the open file db too. */
-       (void)set_write_time(fsp->file_id, fsp->close_write_time);
+       /*
+        * get_existing_share_mode_lock() isn't really the right
+        * call here, as we're being called after
+        * close_remove_share_mode() inside close_normal_file()
+        * so it's quite normal to not have an existing share
+        * mode here. However, get_share_mode_lock() doesn't
+        * work because that will create a new share mode if
+        * one doesn't exist - so stick with this call (just
+        * ignore any error we get if the share mode doesn't
+        * exist.
+        */
 
        lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
        if (lck) {
+               /* On close if we're changing the real file time we
+                * must update it in the open file db too. */
+               (void)set_write_time(fsp->file_id, fsp->close_write_time);
+
                /* Close write times overwrite sticky write times
                   so we must replace any sticky write time here. */
                if (!null_timespec(lck->data->changed_write_time)) {
@@ -662,19 +699,16 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
        NTSTATUS status = NT_STATUS_OK;
        NTSTATUS tmp;
        connection_struct *conn = fsp->conn;
+       int ret;
 
-       if (close_type == ERROR_CLOSE) {
-               cancel_aio_by_fsp(fsp);
-       } else {
-               /*
-                * If we're finishing async io on a close we can get a write
-                * error here, we must remember this.
-                */
-               int ret = wait_for_aio_completion(fsp);
-               if (ret) {
-                       status = ntstatus_keeperror(
-                               status, map_nt_error_from_unix(ret));
-               }
+       /*
+        * If we're finishing async io on a close we can get a write
+        * error here, we must remember this.
+        */
+       ret = wait_for_aio_completion(fsp);
+       if (ret) {
+               status = ntstatus_keeperror(
+                       status, map_nt_error_from_unix(ret));
        }
 
        /*
@@ -865,7 +899,7 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
                return NT_STATUS_OK;
        }
 
-       if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
+       if(((errno == ENOTEMPTY)||(errno == EEXIST)) && *lp_veto_files(SNUM(conn))) {
                /*
                 * Check to see if the only thing in this directory are
                 * vetoed files/directories. If so then delete them and
@@ -1010,6 +1044,7 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
        bool delete_dir = False;
        NTSTATUS status = NT_STATUS_OK;
        NTSTATUS status1 = NT_STATUS_OK;
+       const struct security_token *del_nt_token = NULL;
        const struct security_unix_token *del_token = NULL;
 
        /*
@@ -1044,6 +1079,7 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
                send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
                                               fsp->fsp_name->base_name);
                set_delete_on_close_lck(fsp, lck, true,
+                               get_current_nttok(fsp->conn),
                                get_current_utok(fsp->conn));
                fsp->delete_on_close = true;
                if (became_user) {
@@ -1051,8 +1087,8 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
                }
        }
 
-       del_token = get_delete_on_close_token(lck, fsp->name_hash);
-       delete_dir = (del_token != NULL);
+       delete_dir = get_delete_on_close_token(lck, fsp->name_hash,
+                                       &del_nt_token, &del_token);
 
        if (delete_dir) {
                int i;
@@ -1065,6 +1101,9 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
                                if (fsp->posix_open && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) {
                                        continue;
                                }
+                               if (share_mode_stale_pid(lck->data, i)) {
+                                       continue;
+                               }
                                delete_dir = False;
                                break;
                        }
@@ -1084,7 +1123,7 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
                                del_token->gid,
                                del_token->ngroups,
                                del_token->groups,
-                               NULL);
+                               del_nt_token);
 
                TALLOC_FREE(lck);