pvfs_open: pass down &f->handle->fd to odb_open_file()
[samba.git] / source / ntvfs / posix / pvfs_open.c
index 12b70c00fd9909591c4de2ec91c9e2ef09163fe9..ceda3a6da0b5aa58d5b3aa623b802389b1a045e5 100644 (file)
@@ -50,29 +50,10 @@ struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
 */
 static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
 {
-       int open_count;
-       char *path = NULL;
-
-       if (h->name->stream_name == NULL && 
-           pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
-           open_count == 1) {
-               NTSTATUS status;
-               status = pvfs_xattr_unlink_hook(h->pvfs, path);
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
-                                path, nt_errstr(status)));
-               }
-               if (rmdir(path) != 0) {
-                       DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n", 
-                                path, strerror(errno)));
-               }
-       }
-
-       talloc_free(path);
-
        if (h->have_opendb_entry) {
                struct odb_lock *lck;
                NTSTATUS status;
+               const char *delete_path = NULL;
 
                lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
                if (lck == NULL) {
@@ -80,12 +61,24 @@ static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
                        return 0;
                }
 
-               status = odb_close_file(lck, h);
+               status = odb_close_file(lck, h, &delete_path);
                if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
+                       DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
                                 h->name->full_name, nt_errstr(status)));
                }
 
+               if (h->name->stream_name == NULL && delete_path) {
+                       status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
+                                        delete_path, nt_errstr(status)));
+                       }
+                       if (rmdir(delete_path) != 0) {
+                               DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
+                                        delete_path, strerror(errno)));
+                       }
+               }
+
                talloc_free(lck);
        }
 
@@ -151,8 +144,8 @@ static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
   form the lock context used for opendb locking. Note that we must
   zero here to take account of possible padding on some architectures
 */
-static NTSTATUS pvfs_locking_key(struct pvfs_filename *name, 
-                                TALLOC_CTX *mem_ctx, DATA_BLOB *key)
+NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
+                         TALLOC_CTX *mem_ctx, DATA_BLOB *key)
 {
        struct {
                dev_t device;
@@ -297,10 +290,17 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
                }
                
                /* see if we are allowed to open at the same time as existing opens */
-               status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
-                                      share_access, access_mask, del_on_close, 
-                                      io->generic.in.open_disposition,
-                                      false, OPLOCK_NONE, NULL);
+               status = odb_can_open(lck, name->stream_id,
+                                     share_access, access_mask, del_on_close,
+                                     io->generic.in.open_disposition, false);
+               if (!NT_STATUS_IS_OK(status)) {
+                       talloc_free(lck);
+                       return status;
+               }
+
+               /* now really mark the file as open */
+               status = odb_open_file(lck, f->handle, name->full_name,
+                                      NULL, false, OPLOCK_NONE, NULL);
 
                if (!NT_STATUS_IS_OK(status)) {
                        talloc_free(lck);
@@ -351,10 +351,16 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
 
-               status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
-                                      share_access, access_mask, del_on_close, 
-                                      io->generic.in.open_disposition,
-                                      false, OPLOCK_NONE, NULL);
+               status = odb_can_open(lck, name->stream_id,
+                                     share_access, access_mask, del_on_close,
+                                     io->generic.in.open_disposition, false);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto cleanup_delete;
+               }
+
+               status = odb_open_file(lck, f->handle, name->full_name,
+                                      NULL, false, OPLOCK_NONE, NULL);
 
                if (!NT_STATUS_IS_OK(status)) {
                        goto cleanup_delete;
@@ -410,9 +416,6 @@ cleanup_delete:
 */
 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
 {
-       int open_count;
-       char *path = NULL;
-
        /* the write time is no longer sticky */
        if (h->sticky_write_time) {
                NTSTATUS status;
@@ -441,32 +444,10 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h)
                h->fd = -1;
        }
 
-       if (h->name->stream_name == NULL && 
-           h->open_completed &&
-           pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
-           open_count == 1) {
-               NTSTATUS status;
-               status = pvfs_xattr_unlink_hook(h->pvfs, path);
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
-                                path, nt_errstr(status)));
-               }
-               if (unlink(path) != 0) {
-                       DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n", 
-                                path, strerror(errno)));
-               } else {
-                       notify_trigger(h->pvfs->notify_context, 
-                                      NOTIFY_ACTION_REMOVED, 
-                                      FILE_NOTIFY_CHANGE_FILE_NAME,
-                                      path);
-               }
-       }
-
-       talloc_free(path);
-
        if (h->have_opendb_entry) {
                struct odb_lock *lck;
                NTSTATUS status;
+               const char *delete_path = NULL;
 
                lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
                if (lck == NULL) {
@@ -474,12 +455,30 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h)
                        return 0;
                }
 
-               status = odb_close_file(lck, h);
+               status = odb_close_file(lck, h, &delete_path);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
                                 h->name->full_name, nt_errstr(status)));
                }
 
+               if (h->name->stream_name == NULL &&
+                   h->open_completed && delete_path) {
+                       status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
+                                        delete_path, nt_errstr(status)));
+                       }
+                       if (unlink(delete_path) != 0) {
+                               DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
+                                        delete_path, strerror(errno)));
+                       } else {
+                               notify_trigger(h->pvfs->notify_context,
+                                              NOTIFY_ACTION_REMOVED,
+                                              FILE_NOTIFY_CHANGE_FILE_NAME,
+                                              delete_path);
+                       }
+               }
+
                talloc_free(lck);
        }
 
@@ -558,6 +557,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        bool del_on_close;
        struct pvfs_filename *parent;
        uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
+       bool allow_level_II_oplock = false;
 
        if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
            (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
@@ -574,7 +574,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
                status = pvfs_locking_key(parent, req, &locking_key);
                NT_STATUS_NOT_OK_RETURN(status);
                status = odb_get_delete_on_close(pvfs->odb_context, &locking_key, 
-                                                &del_on_close, NULL, NULL);
+                                                &del_on_close);
                NT_STATUS_NOT_OK_RETURN(status);
                if (del_on_close) {
                        return NT_STATUS_DELETE_PENDING;
@@ -672,20 +672,22 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
                oplock_level = OPLOCK_EXCLUSIVE;
        }
 
-       status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
-                              share_access, access_mask, del_on_close, 
-                              io->generic.in.open_disposition,
-                              false, oplock_level, &oplock_granted);
-       talloc_free(lck);
+       if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
+               allow_level_II_oplock = true;
+       }
+
+       status = odb_can_open(lck, name->stream_id,
+                             share_access, access_mask, del_on_close,
+                             io->generic.in.open_disposition, false);
        if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(lck);
                /* bad news, we must have hit a race - we don't delete the file
-                  here as the most likely scenario is that someone else created 
+                  here as the most likely scenario is that someone else created
                   the file at the same time */
                close(fd);
                return status;
        }
 
-
        f->ntvfs             = h;
        f->pvfs              = pvfs;
        f->pending_list      = NULL;
@@ -708,23 +710,34 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        f->handle->sticky_write_time = false;
        f->handle->open_completed    = false;
 
+       status = odb_open_file(lck, f->handle, name->full_name,
+                              &f->handle->fd, allow_level_II_oplock,
+                              oplock_level, &oplock_granted);
+       talloc_free(lck);
+       if (!NT_STATUS_IS_OK(status)) {
+               /* bad news, we must have hit a race - we don't delete the file
+                  here as the most likely scenario is that someone else created
+                  the file at the same time */
+               close(fd);
+               return status;
+       }
+
        DLIST_ADD(pvfs->files.list, f);
 
+       /* setup a destructor to avoid file descriptor leaks on
+          abnormal termination */
+       talloc_set_destructor(f, pvfs_fnum_destructor);
+       talloc_set_destructor(f->handle, pvfs_handle_destructor);
+
        if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
                oplock_granted = OPLOCK_BATCH;
        } else if (oplock_granted != OPLOCK_NONE) {
                status = pvfs_setup_oplock(f, oplock_granted);
                if (!NT_STATUS_IS_OK(status)) {
-                       talloc_free(lck);
                        return status;
                }
        }
 
-       /* setup a destructor to avoid file descriptor leaks on
-          abnormal termination */
-       talloc_set_destructor(f, pvfs_fnum_destructor);
-       talloc_set_destructor(f->handle, pvfs_handle_destructor);
-
        io->generic.out.oplock_level  = oplock_granted;
        io->generic.out.file.ntvfs    = f->ntvfs;
        io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
@@ -810,7 +823,7 @@ static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
 
 /*
   setup for a retry of a request that was rejected
-  by odb_open_file() or odb_can_open()
+  by odb_can_open()
 */
 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
                              struct ntvfs_request *req,
@@ -1062,6 +1075,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        bool del_on_close;
        bool stream_existed, stream_truncate=false;
        uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
+       bool allow_level_II_oplock = false;
 
        /* use the generic mapping code to avoid implementing all the
           different open calls. */
@@ -1256,11 +1270,14 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                oplock_level = OPLOCK_EXCLUSIVE;
        }
 
+       if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
+               allow_level_II_oplock = true;
+       }
+
        /* see if we are allowed to open at the same time as existing opens */
-       status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
-                              share_access, access_mask, del_on_close,
-                              io->generic.in.open_disposition,
-                              false, oplock_level, &oplock_granted);
+       status = odb_can_open(lck, name->stream_id,
+                             share_access, access_mask, del_on_close,
+                             io->generic.in.open_disposition, false);
 
        /*
         * on a sharing violation we need to retry when the file is closed by
@@ -1279,18 +1296,6 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
                return status;
        }
 
-       if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
-               oplock_granted = OPLOCK_BATCH;
-       } else if (oplock_granted != OPLOCK_NONE) {
-               status = pvfs_setup_oplock(f, oplock_granted);
-               if (!NT_STATUS_IS_OK(status)) {
-                       talloc_free(lck);
-                       return status;
-               }
-       }
-
-       f->handle->have_opendb_entry = true;
-
        if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
                flags |= O_RDWR;
        } else {
@@ -1306,6 +1311,28 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
 
        f->handle->fd = fd;
 
+       /* now really mark the file as open */
+       status = odb_open_file(lck, f->handle, name->full_name,
+                              &f->handle->fd, allow_level_II_oplock,
+                              oplock_level, &oplock_granted);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(lck);
+               return status;
+       }
+
+       if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
+               oplock_granted = OPLOCK_BATCH;
+       } else if (oplock_granted != OPLOCK_NONE) {
+               status = pvfs_setup_oplock(f, oplock_granted);
+               if (!NT_STATUS_IS_OK(status)) {
+                       talloc_free(lck);
+                       return status;
+               }
+       }
+
+       f->handle->have_opendb_entry = true;
+
        stream_existed = name->stream_exists;
 
        /* if this was a stream create then create the stream as well */
@@ -1530,7 +1557,7 @@ NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
 
        status = odb_can_open(lck, name->stream_id,
                              share_access, access_mask, delete_on_close,
-                             0, false);
+                             NTCREATEX_DISP_OPEN, false);
 
        if (NT_STATUS_IS_OK(status)) {
                status = pvfs_access_check_simple(pvfs, req, name, access_mask);
@@ -1594,7 +1621,7 @@ NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
 
        status = odb_can_open(lck, name->stream_id,
                              share_access, access_mask, delete_on_close,
-                             0, false);
+                             NTCREATEX_DISP_OPEN, false);
 
        /*
         * if it's a sharing violation or we got no oplock
@@ -1648,15 +1675,25 @@ NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       /* TODO: this may needs some more flags */
-       share_access    = NTCREATEX_SHARE_ACCESS_WRITE;
-       access_mask     = 0;
+       share_access    = NTCREATEX_SHARE_ACCESS_READ |
+                         NTCREATEX_SHARE_ACCESS_WRITE |
+                         NTCREATEX_SHARE_ACCESS_DELETE;
+       /*
+        * I would have thought that we would need to pass
+        * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
+        *
+        * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
+        * to set the filesize.
+        *
+        * --metze
+        */
+       access_mask     = SEC_FILE_WRITE_ATTRIBUTE;
        delete_on_close = false;
        break_to_none   = true;
 
        status = odb_can_open(lck, name->stream_id,
                              share_access, access_mask, delete_on_close,
-                             0, break_to_none);
+                             NTCREATEX_DISP_OPEN, break_to_none);
 
        /*
         * if it's a sharing violation or we got no oplock
@@ -1710,12 +1747,12 @@ NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
 
        share_access    = NTCREATEX_SHARE_ACCESS_READ |
                          NTCREATEX_SHARE_ACCESS_WRITE;
-       access_mask     = 0;
+       access_mask     = SEC_FILE_READ_ATTRIBUTE;
        delete_on_close = false;
 
        status = odb_can_open(lck, name->stream_id,
                              share_access, access_mask, delete_on_close,
-                             0, false);
+                             NTCREATEX_DISP_OPEN, false);
 
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(lck);
@@ -1728,14 +1765,13 @@ NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
 /*
   determine if delete on close is set on 
 */
-bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h, 
-                             int *open_count, char **path)
+bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
 {
        NTSTATUS status;
        bool del_on_close;
 
        status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key, 
-                                        &del_on_close, open_count, path);
+                                        &del_on_close);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
                return false;