2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - open and close
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "vfs_posix.h"
24 #include "system/dir.h"
25 #include "system/time.h"
26 #include "lib/util/dlinklist.h"
27 #include "messaging/messaging.h"
28 #include "librpc/gen_ndr/xattr.h"
31 find open file handle given fnum
33 struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
34 struct ntvfs_request *req, struct ntvfs_handle *h)
39 p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs);
42 f = talloc_get_type(p, struct pvfs_file);
49 cleanup a open directory handle
51 static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
53 if (h->have_opendb_entry) {
56 const char *delete_path = NULL;
58 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
60 DEBUG(0,("Unable to lock opendb for close\n"));
64 status = odb_close_file(lck, h, &delete_path);
65 if (!NT_STATUS_IS_OK(status)) {
66 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
67 h->name->full_name, nt_errstr(status)));
70 if (h->name->stream_name == NULL && delete_path) {
71 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
72 if (!NT_STATUS_IS_OK(status)) {
73 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
74 delete_path, nt_errstr(status)));
76 if (rmdir(delete_path) != 0) {
77 DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
78 delete_path, strerror(errno)));
89 cleanup a open directory fnum
91 static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
93 DLIST_REMOVE(f->pvfs->files.list, f);
94 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
100 setup any EAs and the ACL on newly created files/directories
102 static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
103 struct ntvfs_request *req,
104 struct pvfs_filename *name,
105 int fd, struct pvfs_file *f,
110 /* setup any EAs that were asked for */
111 if (io->ntcreatex.in.ea_list) {
112 status = pvfs_setfileinfo_ea_set(pvfs, name, fd,
113 io->ntcreatex.in.ea_list->num_eas,
114 io->ntcreatex.in.ea_list->eas);
115 if (!NT_STATUS_IS_OK(status)) {
120 /* setup an initial sec_desc if requested */
121 if (io->ntcreatex.in.sec_desc) {
122 union smb_setfileinfo set;
124 * TODO: set the full ACL!
125 * - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
126 * when a SACL is present on the sd,
127 * but the user doesn't have SeSecurityPrivilege
130 set.set_secdesc.in.file.ntvfs = f->ntvfs;
131 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
132 set.set_secdesc.in.sd = io->ntcreatex.in.sec_desc;
134 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
136 /* otherwise setup an inherited acl from the parent */
137 status = pvfs_acl_inherit(pvfs, req, name, fd);
144 form the lock context used for opendb locking. Note that we must
145 zero here to take account of possible padding on some architectures
147 NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
148 TALLOC_CTX *mem_ctx, DATA_BLOB *key)
154 ZERO_STRUCT(lock_context);
156 lock_context.device = name->st.st_dev;
157 lock_context.inode = name->st.st_ino;
159 *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
160 if (key->data == NULL) {
161 return NT_STATUS_NO_MEMORY;
171 static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
172 struct ntvfs_request *req,
173 struct pvfs_filename *name,
177 struct ntvfs_handle *h;
179 uint32_t create_action;
180 uint32_t access_mask = io->generic.in.access_mask;
181 struct odb_lock *lck;
183 uint32_t create_options;
184 uint32_t share_access;
186 create_options = io->generic.in.create_options;
187 share_access = io->generic.in.share_access;
189 if (name->stream_name) {
190 return NT_STATUS_NOT_A_DIRECTORY;
193 /* if the client says it must be a directory, and it isn't,
195 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
196 return NT_STATUS_NOT_A_DIRECTORY;
199 switch (io->generic.in.open_disposition) {
200 case NTCREATEX_DISP_OPEN_IF:
203 case NTCREATEX_DISP_OPEN:
205 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
209 case NTCREATEX_DISP_CREATE:
211 return NT_STATUS_OBJECT_NAME_COLLISION;
215 case NTCREATEX_DISP_OVERWRITE_IF:
216 case NTCREATEX_DISP_OVERWRITE:
217 case NTCREATEX_DISP_SUPERSEDE:
219 return NT_STATUS_INVALID_PARAMETER;
222 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
223 NT_STATUS_NOT_OK_RETURN(status);
225 f = talloc(h, struct pvfs_file);
227 return NT_STATUS_NO_MEMORY;
230 f->handle = talloc(f, struct pvfs_file_handle);
231 if (f->handle == NULL) {
232 return NT_STATUS_NO_MEMORY;
236 /* check the security descriptor */
237 status = pvfs_access_check(pvfs, req, name, &access_mask);
239 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
241 if (!NT_STATUS_IS_OK(status)) {
247 f->pending_list = NULL;
249 f->share_access = io->generic.in.share_access;
250 f->impersonation = io->generic.in.impersonation;
251 f->access_mask = access_mask;
252 f->brl_handle = NULL;
253 f->notify_buffer = NULL;
256 f->handle->pvfs = pvfs;
257 f->handle->name = talloc_steal(f->handle, name);
259 f->handle->odb_locking_key = data_blob(NULL, 0);
260 f->handle->create_options = io->generic.in.create_options;
261 f->handle->seek_offset = 0;
262 f->handle->position = 0;
264 f->handle->oplock = NULL;
265 f->handle->sticky_write_time = false;
266 f->handle->open_completed = false;
268 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
269 pvfs_directory_empty(pvfs, f->handle->name)) {
272 del_on_close = false;
276 /* form the lock context used for opendb locking */
277 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
278 if (!NT_STATUS_IS_OK(status)) {
282 /* get a lock on this file before the actual open */
283 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
285 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
287 /* we were supposed to do a blocking lock, so something
289 return NT_STATUS_INTERNAL_DB_CORRUPTION;
292 /* see if we are allowed to open at the same time as existing opens */
293 status = odb_can_open(lck, name->stream_id,
294 share_access, access_mask, del_on_close,
295 io->generic.in.open_disposition, false);
296 if (!NT_STATUS_IS_OK(status)) {
301 /* now really mark the file as open */
302 status = odb_open_file(lck, f->handle, name->full_name,
303 NULL, false, OPLOCK_NONE, NULL);
305 if (!NT_STATUS_IS_OK(status)) {
310 f->handle->have_opendb_entry = true;
313 DLIST_ADD(pvfs->files.list, f);
315 /* setup destructors to avoid leaks on abnormal termination */
316 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
317 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
320 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
321 mode_t mode = pvfs_fileperms(pvfs, attrib);
323 if (mkdir(name->full_name, mode) == -1) {
324 return pvfs_map_errno(pvfs,errno);
327 pvfs_xattr_unlink_hook(pvfs, name->full_name);
329 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
330 if (!NT_STATUS_IS_OK(status)) {
334 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
335 if (!NT_STATUS_IS_OK(status)) {
339 /* form the lock context used for opendb locking */
340 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
341 if (!NT_STATUS_IS_OK(status)) {
345 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
347 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
349 /* we were supposed to do a blocking lock, so something
351 return NT_STATUS_INTERNAL_DB_CORRUPTION;
354 status = odb_can_open(lck, name->stream_id,
355 share_access, access_mask, del_on_close,
356 io->generic.in.open_disposition, false);
358 if (!NT_STATUS_IS_OK(status)) {
362 status = odb_open_file(lck, f->handle, name->full_name,
363 NULL, false, OPLOCK_NONE, NULL);
365 if (!NT_STATUS_IS_OK(status)) {
369 f->handle->have_opendb_entry = true;
371 create_action = NTCREATEX_ACTION_CREATED;
373 notify_trigger(pvfs->notify_context,
375 FILE_NOTIFY_CHANGE_DIR_NAME,
378 create_action = NTCREATEX_ACTION_EXISTED;
382 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
385 /* the open succeeded, keep this handle permanently */
386 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
387 if (!NT_STATUS_IS_OK(status)) {
391 f->handle->open_completed = true;
393 io->generic.out.oplock_level = OPLOCK_NONE;
394 io->generic.out.file.ntvfs = h;
395 io->generic.out.create_action = create_action;
396 io->generic.out.create_time = name->dos.create_time;
397 io->generic.out.access_time = name->dos.access_time;
398 io->generic.out.write_time = name->dos.write_time;
399 io->generic.out.change_time = name->dos.change_time;
400 io->generic.out.attrib = name->dos.attrib;
401 io->generic.out.alloc_size = name->dos.alloc_size;
402 io->generic.out.size = name->st.st_size;
403 io->generic.out.file_type = FILE_TYPE_DISK;
404 io->generic.out.ipc_state = 0;
405 io->generic.out.is_directory = 1;
410 rmdir(name->full_name);
415 destroy a struct pvfs_file_handle
417 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
419 /* the write time is no longer sticky */
420 if (h->sticky_write_time) {
422 status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
423 if (NT_STATUS_IS_OK(status)) {
424 h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
425 pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
429 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
430 h->name->stream_name) {
432 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
433 if (!NT_STATUS_IS_OK(status)) {
434 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
435 h->name->stream_name, h->name->full_name));
440 if (close(h->fd) != 0) {
441 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
442 h->fd, h->name->full_name, strerror(errno)));
447 if (h->have_opendb_entry) {
448 struct odb_lock *lck;
450 const char *delete_path = NULL;
452 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
454 DEBUG(0,("Unable to lock opendb for close\n"));
458 status = odb_close_file(lck, h, &delete_path);
459 if (!NT_STATUS_IS_OK(status)) {
460 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
461 h->name->full_name, nt_errstr(status)));
464 if (h->name->stream_name == NULL &&
465 h->open_completed && delete_path) {
466 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
467 if (!NT_STATUS_IS_OK(status)) {
468 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
469 delete_path, nt_errstr(status)));
471 if (unlink(delete_path) != 0) {
472 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
473 delete_path, strerror(errno)));
475 notify_trigger(h->pvfs->notify_context,
476 NOTIFY_ACTION_REMOVED,
477 FILE_NOTIFY_CHANGE_FILE_NAME,
490 destroy a struct pvfs_file
492 static int pvfs_fnum_destructor(struct pvfs_file *f)
494 DLIST_REMOVE(f->pvfs->files.list, f);
495 pvfs_lock_close(f->pvfs, f);
496 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
503 form the lock context used for byte range locking. This is separate
504 from the locking key used for opendb locking as it needs to take
505 account of file streams (each stream is a separate byte range
508 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
509 struct pvfs_filename *name,
510 struct ntvfs_handle *ntvfs,
511 struct brl_handle **_h)
513 DATA_BLOB odb_key, key;
515 struct brl_handle *h;
517 status = pvfs_locking_key(name, mem_ctx, &odb_key);
518 NT_STATUS_NOT_OK_RETURN(status);
520 if (name->stream_name == NULL) {
523 key = data_blob_talloc(mem_ctx, NULL,
524 odb_key.length + strlen(name->stream_name) + 1);
525 NT_STATUS_HAVE_NO_MEMORY(key.data);
526 memcpy(key.data, odb_key.data, odb_key.length);
527 memcpy(key.data + odb_key.length,
528 name->stream_name, strlen(name->stream_name) + 1);
529 data_blob_free(&odb_key);
532 h = brl_create_handle(mem_ctx, ntvfs, &key);
533 NT_STATUS_HAVE_NO_MEMORY(h);
542 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
543 struct ntvfs_request *req,
544 struct pvfs_filename *name,
549 struct ntvfs_handle *h;
551 struct odb_lock *lck;
552 uint32_t create_options = io->generic.in.create_options;
553 uint32_t share_access = io->generic.in.share_access;
554 uint32_t access_mask = io->generic.in.access_mask;
558 struct pvfs_filename *parent;
559 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
560 bool allow_level_II_oplock = false;
562 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
563 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
564 return NT_STATUS_CANNOT_DELETE;
567 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
568 NT_STATUS_NOT_OK_RETURN(status);
570 /* check that the parent isn't opened with delete on close set */
571 status = pvfs_resolve_parent(pvfs, req, name, &parent);
572 if (NT_STATUS_IS_OK(status)) {
573 DATA_BLOB locking_key;
574 status = pvfs_locking_key(parent, req, &locking_key);
575 NT_STATUS_NOT_OK_RETURN(status);
576 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key,
578 NT_STATUS_NOT_OK_RETURN(status);
580 return NT_STATUS_DELETE_PENDING;
584 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
590 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
591 NT_STATUS_NOT_OK_RETURN(status);
593 f = talloc(h, struct pvfs_file);
594 NT_STATUS_HAVE_NO_MEMORY(f);
596 f->handle = talloc(f, struct pvfs_file_handle);
597 NT_STATUS_HAVE_NO_MEMORY(f->handle);
599 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
600 mode = pvfs_fileperms(pvfs, attrib);
602 /* create the file */
603 fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
605 return pvfs_map_errno(pvfs, errno);
608 pvfs_xattr_unlink_hook(pvfs, name->full_name);
610 /* if this was a stream create then create the stream as well */
611 if (name->stream_name) {
612 status = pvfs_stream_create(pvfs, name, fd);
613 if (!NT_STATUS_IS_OK(status)) {
619 /* re-resolve the open fd */
620 status = pvfs_resolve_name_fd(pvfs, fd, name);
621 if (!NT_STATUS_IS_OK(status)) {
626 name->dos.attrib = attrib;
627 status = pvfs_dosattrib_save(pvfs, name, fd);
628 if (!NT_STATUS_IS_OK(status)) {
633 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
634 if (!NT_STATUS_IS_OK(status)) {
638 /* form the lock context used for byte range locking and
640 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
641 if (!NT_STATUS_IS_OK(status)) {
645 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
646 if (!NT_STATUS_IS_OK(status)) {
650 /* grab a lock on the open file record */
651 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
653 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
655 /* we were supposed to do a blocking lock, so something
657 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
661 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
664 del_on_close = false;
667 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
668 oplock_level = OPLOCK_NONE;
669 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
670 oplock_level = OPLOCK_BATCH;
671 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
672 oplock_level = OPLOCK_EXCLUSIVE;
675 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
676 allow_level_II_oplock = true;
679 status = odb_can_open(lck, name->stream_id,
680 share_access, access_mask, del_on_close,
681 io->generic.in.open_disposition, false);
682 if (!NT_STATUS_IS_OK(status)) {
684 /* bad news, we must have hit a race - we don't delete the file
685 here as the most likely scenario is that someone else created
686 the file at the same time */
693 f->pending_list = NULL;
695 f->share_access = io->generic.in.share_access;
696 f->access_mask = access_mask;
697 f->impersonation = io->generic.in.impersonation;
698 f->notify_buffer = NULL;
701 f->handle->pvfs = pvfs;
702 f->handle->name = talloc_steal(f->handle, name);
704 f->handle->create_options = io->generic.in.create_options;
705 f->handle->seek_offset = 0;
706 f->handle->position = 0;
708 f->handle->oplock = NULL;
709 f->handle->have_opendb_entry = true;
710 f->handle->sticky_write_time = false;
711 f->handle->open_completed = false;
713 status = odb_open_file(lck, f->handle, name->full_name,
714 &f->handle->fd, allow_level_II_oplock,
715 oplock_level, &oplock_granted);
717 if (!NT_STATUS_IS_OK(status)) {
718 /* bad news, we must have hit a race - we don't delete the file
719 here as the most likely scenario is that someone else created
720 the file at the same time */
725 DLIST_ADD(pvfs->files.list, f);
727 /* setup a destructor to avoid file descriptor leaks on
728 abnormal termination */
729 talloc_set_destructor(f, pvfs_fnum_destructor);
730 talloc_set_destructor(f->handle, pvfs_handle_destructor);
732 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
733 oplock_granted = OPLOCK_BATCH;
734 } else if (oplock_granted != OPLOCK_NONE) {
735 status = pvfs_setup_oplock(f, oplock_granted);
736 if (!NT_STATUS_IS_OK(status)) {
741 io->generic.out.oplock_level = oplock_granted;
742 io->generic.out.file.ntvfs = f->ntvfs;
743 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
744 io->generic.out.create_time = name->dos.create_time;
745 io->generic.out.access_time = name->dos.access_time;
746 io->generic.out.write_time = name->dos.write_time;
747 io->generic.out.change_time = name->dos.change_time;
748 io->generic.out.attrib = name->dos.attrib;
749 io->generic.out.alloc_size = name->dos.alloc_size;
750 io->generic.out.size = name->st.st_size;
751 io->generic.out.file_type = FILE_TYPE_DISK;
752 io->generic.out.ipc_state = 0;
753 io->generic.out.is_directory = 0;
755 /* success - keep the file handle */
756 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
757 if (!NT_STATUS_IS_OK(status)) {
761 f->handle->open_completed = true;
763 notify_trigger(pvfs->notify_context,
765 FILE_NOTIFY_CHANGE_FILE_NAME,
772 unlink(name->full_name);
777 state of a pending retry
779 struct pvfs_odb_retry {
780 struct ntvfs_module_context *ntvfs;
781 struct ntvfs_request *req;
782 DATA_BLOB odb_locking_key;
785 void (*callback)(struct pvfs_odb_retry *r,
786 struct ntvfs_module_context *ntvfs,
787 struct ntvfs_request *req,
790 enum pvfs_wait_notice reason);
793 /* destroy a pending request */
794 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
796 struct pvfs_state *pvfs = r->ntvfs->private_data;
797 if (r->odb_locking_key.data) {
798 struct odb_lock *lck;
799 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
801 odb_remove_pending(lck, r);
808 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
810 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
812 if (reason == PVFS_WAIT_EVENT) {
814 * The pending odb entry is already removed.
815 * We use a null locking key to indicate this
818 data_blob_free(&r->odb_locking_key);
821 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
825 setup for a retry of a request that was rejected
828 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
829 struct ntvfs_request *req,
830 struct odb_lock *lck,
831 struct timeval end_time,
834 void (*callback)(struct pvfs_odb_retry *r,
835 struct ntvfs_module_context *ntvfs,
836 struct ntvfs_request *req,
839 enum pvfs_wait_notice reason))
841 struct pvfs_state *pvfs = ntvfs->private_data;
842 struct pvfs_odb_retry *r;
843 struct pvfs_wait *wait_handle;
846 r = talloc(req, struct pvfs_odb_retry);
847 NT_STATUS_HAVE_NO_MEMORY(r);
852 r->private_data = private_data;
853 r->callback = callback;
854 r->odb_locking_key = odb_get_key(r, lck);
855 if (r->odb_locking_key.data == NULL) {
856 return NT_STATUS_NO_MEMORY;
859 /* setup a pending lock */
860 status = odb_open_file_pending(lck, r);
861 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
863 * maybe only a unix application
866 data_blob_free(&r->odb_locking_key);
867 } else if (!NT_STATUS_IS_OK(status)) {
873 talloc_set_destructor(r, pvfs_odb_retry_destructor);
875 wait_handle = pvfs_wait_message(pvfs, req,
876 MSG_PVFS_RETRY_OPEN, end_time,
877 pvfs_odb_retry_callback, r);
878 if (wait_handle == NULL) {
879 return NT_STATUS_NO_MEMORY;
882 talloc_steal(r, wait_handle);
888 retry an open after a sharing violation
890 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
891 struct ntvfs_module_context *ntvfs,
892 struct ntvfs_request *req,
895 enum pvfs_wait_notice reason)
897 union smb_open *io = talloc_get_type(_io, union smb_open);
898 struct timeval *final_timeout = NULL;
902 final_timeout = talloc_get_type(private_data,
906 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
907 just a bug in their server, but we better do the same */
908 if (reason == PVFS_WAIT_CANCEL) {
912 if (reason == PVFS_WAIT_TIMEOUT) {
914 !timeval_expired(final_timeout)) {
916 * we need to retry periodictly
917 * after an EAGAIN as there's
918 * no way the kernel tell us
919 * an oplock is released.
923 /* if it timed out, then give the failure
926 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
927 req->async_states->send_fn(req);
934 /* try the open again, which could trigger another retry setup
935 if it wants to, so we have to unmark the async flag so we
936 will know if it does a second async reply */
937 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
939 status = pvfs_open(ntvfs, req, io);
940 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
941 /* the 2nd try also replied async, so we don't send
946 /* re-mark it async, just in case someone up the chain does
948 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
950 /* send the reply up the chain */
951 req->async_states->status = status;
952 req->async_states->send_fn(req);
957 special handling for openx DENY_DOS semantics
959 This function attempts a reference open using an existing handle. If its allowed,
960 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
961 open processing continues.
963 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
964 struct ntvfs_request *req, union smb_open *io,
965 struct pvfs_file *f, struct odb_lock *lck)
967 struct pvfs_state *pvfs = ntvfs->private_data;
968 struct pvfs_file *f2;
969 struct pvfs_filename *name;
972 /* search for an existing open with the right parameters. Note
973 the magic ntcreatex options flag, which is set in the
974 generic mapping code. This might look ugly, but its
975 actually pretty much now w2k does it internally as well.
977 If you look at the BASE-DENYDOS test you will see that a
978 DENY_DOS is a very special case, and in the right
979 circumstances you actually get the _same_ handle back
980 twice, rather than a new handle.
982 for (f2=pvfs->files.list;f2;f2=f2->next) {
984 f2->ntvfs->session_info == req->session_info &&
985 f2->ntvfs->smbpid == req->smbpid &&
986 (f2->handle->create_options &
987 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
988 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
989 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
990 strcasecmp_m(f2->handle->name->original_name,
991 io->generic.in.fname)==0) {
997 return NT_STATUS_SHARING_VIOLATION;
1000 /* quite an insane set of semantics ... */
1001 if (is_exe_filename(io->generic.in.fname) &&
1002 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1003 return NT_STATUS_SHARING_VIOLATION;
1007 setup a reference to the existing handle
1009 talloc_free(f->handle);
1010 f->handle = talloc_reference(f, f2->handle);
1014 name = f->handle->name;
1016 io->generic.out.oplock_level = OPLOCK_NONE;
1017 io->generic.out.file.ntvfs = f->ntvfs;
1018 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1019 io->generic.out.create_time = name->dos.create_time;
1020 io->generic.out.access_time = name->dos.access_time;
1021 io->generic.out.write_time = name->dos.write_time;
1022 io->generic.out.change_time = name->dos.change_time;
1023 io->generic.out.attrib = name->dos.attrib;
1024 io->generic.out.alloc_size = name->dos.alloc_size;
1025 io->generic.out.size = name->st.st_size;
1026 io->generic.out.file_type = FILE_TYPE_DISK;
1027 io->generic.out.ipc_state = 0;
1028 io->generic.out.is_directory = 0;
1030 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1031 NT_STATUS_NOT_OK_RETURN(status);
1033 return NT_STATUS_OK;
1039 setup for a open retry after a sharing violation
1041 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1042 struct ntvfs_request *req,
1044 struct pvfs_file *f,
1045 struct odb_lock *lck,
1046 NTSTATUS parent_status)
1048 struct pvfs_state *pvfs = ntvfs->private_data;
1050 struct timeval end_time;
1051 struct timeval *final_timeout = NULL;
1053 if (io->generic.in.create_options &
1054 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1055 /* see if we can satisfy the request using the special DENY_DOS
1057 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1058 if (NT_STATUS_IS_OK(status)) {
1063 /* the retry should allocate a new file handle */
1066 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1067 end_time = timeval_add(&req->statistics.request_time,
1068 0, pvfs->sharing_violation_delay);
1069 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1070 end_time = timeval_add(&req->statistics.request_time,
1071 pvfs->oplock_break_timeout, 0);
1072 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1074 * we got EAGAIN which means a unix application
1075 * has an oplock or share mode
1077 * we retry every 4/5 of the sharing violation delay
1078 * to see if the unix application
1079 * has released the oplock or share mode.
1081 final_timeout = talloc(req, struct timeval);
1082 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1083 *final_timeout = timeval_add(&req->statistics.request_time,
1084 pvfs->oplock_break_timeout,
1086 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1087 end_time = timeval_min(final_timeout, &end_time);
1089 return NT_STATUS_INTERNAL_ERROR;
1092 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1093 final_timeout, pvfs_retry_open_sharing);
1099 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1100 struct ntvfs_request *req, union smb_open *io)
1102 struct pvfs_state *pvfs = ntvfs->private_data;
1104 struct pvfs_filename *name;
1105 struct pvfs_file *f;
1106 struct ntvfs_handle *h;
1109 struct odb_lock *lck;
1110 uint32_t create_options;
1111 uint32_t share_access;
1112 uint32_t access_mask;
1114 bool stream_existed, stream_truncate=false;
1115 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1116 bool allow_level_II_oplock = false;
1118 /* use the generic mapping code to avoid implementing all the
1119 different open calls. */
1120 if (io->generic.level != RAW_OPEN_GENERIC &&
1121 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1122 return ntvfs_map_open(ntvfs, req, io);
1125 /* resolve the cifs name to a posix name */
1126 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1127 PVFS_RESOLVE_STREAMS, &name);
1128 if (!NT_STATUS_IS_OK(status)) {
1132 /* directory opens are handled separately */
1133 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1134 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1135 return pvfs_open_directory(pvfs, req, name, io);
1138 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1139 open doesn't match */
1140 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1142 create_options = io->generic.in.create_options;
1143 share_access = io->generic.in.share_access;
1144 access_mask = io->generic.in.access_mask;
1146 /* certain create options are not allowed */
1147 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1148 !(access_mask & SEC_STD_DELETE)) {
1149 return NT_STATUS_INVALID_PARAMETER;
1154 switch (io->generic.in.open_disposition) {
1155 case NTCREATEX_DISP_SUPERSEDE:
1156 case NTCREATEX_DISP_OVERWRITE_IF:
1157 if (name->stream_name == NULL) {
1160 stream_truncate = true;
1164 case NTCREATEX_DISP_OPEN:
1165 if (!name->stream_exists) {
1166 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1171 case NTCREATEX_DISP_OVERWRITE:
1172 if (!name->stream_exists) {
1173 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1175 if (name->stream_name == NULL) {
1178 stream_truncate = true;
1182 case NTCREATEX_DISP_CREATE:
1183 if (name->stream_exists) {
1184 return NT_STATUS_OBJECT_NAME_COLLISION;
1189 case NTCREATEX_DISP_OPEN_IF:
1194 return NT_STATUS_INVALID_PARAMETER;
1197 /* handle creating a new file separately */
1198 if (!name->exists) {
1199 status = pvfs_create_file(pvfs, req, name, io);
1200 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1204 /* we've hit a race - the file was created during this call */
1205 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1209 /* try re-resolving the name */
1210 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1211 if (!NT_STATUS_IS_OK(status)) {
1214 /* fall through to a normal open */
1217 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1218 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1219 return NT_STATUS_CANNOT_DELETE;
1222 /* check the security descriptor */
1223 status = pvfs_access_check(pvfs, req, name, &access_mask);
1224 if (!NT_STATUS_IS_OK(status)) {
1228 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1229 NT_STATUS_NOT_OK_RETURN(status);
1231 f = talloc(h, struct pvfs_file);
1233 return NT_STATUS_NO_MEMORY;
1236 f->handle = talloc(f, struct pvfs_file_handle);
1237 if (f->handle == NULL) {
1238 return NT_STATUS_NO_MEMORY;
1243 f->pending_list = NULL;
1245 f->share_access = io->generic.in.share_access;
1246 f->access_mask = access_mask;
1247 f->impersonation = io->generic.in.impersonation;
1248 f->notify_buffer = NULL;
1251 f->handle->pvfs = pvfs;
1253 f->handle->name = talloc_steal(f->handle, name);
1254 f->handle->create_options = io->generic.in.create_options;
1255 f->handle->seek_offset = 0;
1256 f->handle->position = 0;
1257 f->handle->mode = 0;
1258 f->handle->oplock = NULL;
1259 f->handle->have_opendb_entry = false;
1260 f->handle->sticky_write_time = false;
1261 f->handle->open_completed = false;
1263 /* form the lock context used for byte range locking and
1265 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1266 if (!NT_STATUS_IS_OK(status)) {
1270 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1271 if (!NT_STATUS_IS_OK(status)) {
1275 /* get a lock on this file before the actual open */
1276 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1278 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1280 /* we were supposed to do a blocking lock, so something
1282 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1285 DLIST_ADD(pvfs->files.list, f);
1287 /* setup a destructor to avoid file descriptor leaks on
1288 abnormal termination */
1289 talloc_set_destructor(f, pvfs_fnum_destructor);
1290 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1293 * Only SMB2 takes care of the delete_on_close,
1296 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1297 req->ctx->protocol == PROTOCOL_SMB2) {
1298 del_on_close = true;
1300 del_on_close = false;
1303 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1304 oplock_level = OPLOCK_NONE;
1305 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1306 oplock_level = OPLOCK_BATCH;
1307 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1308 oplock_level = OPLOCK_EXCLUSIVE;
1311 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1312 allow_level_II_oplock = true;
1315 /* see if we are allowed to open at the same time as existing opens */
1316 status = odb_can_open(lck, name->stream_id,
1317 share_access, access_mask, del_on_close,
1318 io->generic.in.open_disposition, false);
1321 * on a sharing violation we need to retry when the file is closed by
1322 * the other user, or after 1 second
1323 * on a non granted oplock we need to retry when the file is closed by
1324 * the other user, or after 30 seconds
1326 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1327 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1328 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1329 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1332 if (!NT_STATUS_IS_OK(status)) {
1337 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1343 /* do the actual open */
1344 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1346 status = pvfs_map_errno(f->pvfs, errno);
1349 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1351 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1352 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1353 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1362 /* now really mark the file as open */
1363 status = odb_open_file(lck, f->handle, name->full_name,
1364 &f->handle->fd, allow_level_II_oplock,
1365 oplock_level, &oplock_granted);
1367 if (!NT_STATUS_IS_OK(status)) {
1372 f->handle->have_opendb_entry = true;
1374 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1375 oplock_granted = OPLOCK_BATCH;
1376 } else if (oplock_granted != OPLOCK_NONE) {
1377 status = pvfs_setup_oplock(f, oplock_granted);
1378 if (!NT_STATUS_IS_OK(status)) {
1384 stream_existed = name->stream_exists;
1386 /* if this was a stream create then create the stream as well */
1387 if (!name->stream_exists) {
1388 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1389 if (!NT_STATUS_IS_OK(status)) {
1393 if (stream_truncate) {
1394 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1395 if (!NT_STATUS_IS_OK(status)) {
1402 /* re-resolve the open fd */
1403 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1404 if (!NT_STATUS_IS_OK(status)) {
1409 if (f->handle->name->stream_id == 0 &&
1410 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1411 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1412 /* for overwrite we need to replace file permissions */
1413 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1414 mode_t mode = pvfs_fileperms(pvfs, attrib);
1415 if (fchmod(fd, mode) == -1) {
1417 return pvfs_map_errno(pvfs, errno);
1419 name->dos.attrib = attrib;
1420 status = pvfs_dosattrib_save(pvfs, name, fd);
1421 if (!NT_STATUS_IS_OK(status)) {
1429 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1430 NT_STATUS_NOT_OK_RETURN(status);
1432 /* mark the open as having completed fully, so delete on close
1434 f->handle->open_completed = true;
1436 io->generic.out.oplock_level = oplock_granted;
1437 io->generic.out.file.ntvfs = h;
1438 io->generic.out.create_action = stream_existed?
1439 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1440 io->generic.out.create_time = name->dos.create_time;
1441 io->generic.out.access_time = name->dos.access_time;
1442 io->generic.out.write_time = name->dos.write_time;
1443 io->generic.out.change_time = name->dos.change_time;
1444 io->generic.out.attrib = name->dos.attrib;
1445 io->generic.out.alloc_size = name->dos.alloc_size;
1446 io->generic.out.size = name->st.st_size;
1447 io->generic.out.file_type = FILE_TYPE_DISK;
1448 io->generic.out.ipc_state = 0;
1449 io->generic.out.is_directory = 0;
1451 return NT_STATUS_OK;
1458 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1459 struct ntvfs_request *req, union smb_close *io)
1461 struct pvfs_state *pvfs = ntvfs->private_data;
1462 struct pvfs_file *f;
1463 struct utimbuf unix_times;
1465 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1466 return NT_STATUS_DOS(ERRSRV, ERRerror);
1469 if (io->generic.level != RAW_CLOSE_CLOSE) {
1470 return ntvfs_map_close(ntvfs, req, io);
1473 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1475 return NT_STATUS_INVALID_HANDLE;
1478 if (!null_time(io->close.in.write_time)) {
1479 unix_times.actime = 0;
1480 unix_times.modtime = io->close.in.write_time;
1481 utime(f->handle->name->full_name, &unix_times);
1482 } else if (f->handle->sticky_write_time) {
1483 unix_times.actime = 0;
1484 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1485 utime(f->handle->name->full_name, &unix_times);
1490 return NT_STATUS_OK;
1495 logoff - close all file descriptors open by a vuid
1497 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1498 struct ntvfs_request *req)
1500 struct pvfs_state *pvfs = ntvfs->private_data;
1501 struct pvfs_file *f, *next;
1503 for (f=pvfs->files.list;f;f=next) {
1505 if (f->ntvfs->session_info == req->session_info) {
1510 return NT_STATUS_OK;
1515 exit - close files for the current pid
1517 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1518 struct ntvfs_request *req)
1520 struct pvfs_state *pvfs = ntvfs->private_data;
1521 struct pvfs_file *f, *next;
1523 for (f=pvfs->files.list;f;f=next) {
1525 if (f->ntvfs->session_info == req->session_info &&
1526 f->ntvfs->smbpid == req->smbpid) {
1531 return NT_STATUS_OK;
1536 change the delete on close flag on an already open file
1538 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1539 struct ntvfs_request *req,
1540 struct pvfs_file *f, bool del_on_close)
1542 struct odb_lock *lck;
1545 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1546 return NT_STATUS_CANNOT_DELETE;
1549 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1550 !pvfs_directory_empty(pvfs, f->handle->name)) {
1551 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1555 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1557 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1560 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1562 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1565 status = odb_set_delete_on_close(lck, del_on_close);
1574 determine if a file can be deleted, or if it is prevented by an
1577 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1578 struct ntvfs_request *req,
1579 struct pvfs_filename *name,
1580 struct odb_lock **lckp)
1584 struct odb_lock *lck;
1585 uint32_t share_access;
1586 uint32_t access_mask;
1587 bool delete_on_close;
1589 status = pvfs_locking_key(name, name, &key);
1590 if (!NT_STATUS_IS_OK(status)) {
1591 return NT_STATUS_NO_MEMORY;
1594 lck = odb_lock(req, pvfs->odb_context, &key);
1596 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1597 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1600 share_access = NTCREATEX_SHARE_ACCESS_READ |
1601 NTCREATEX_SHARE_ACCESS_WRITE |
1602 NTCREATEX_SHARE_ACCESS_DELETE;
1603 access_mask = SEC_STD_DELETE;
1604 delete_on_close = true;
1606 status = odb_can_open(lck, name->stream_id,
1607 share_access, access_mask, delete_on_close,
1608 NTCREATEX_DISP_OPEN, false);
1610 if (NT_STATUS_IS_OK(status)) {
1611 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1615 * if it's a sharing violation or we got no oplock
1616 * only keep the lock if the caller requested access
1619 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1620 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1626 } else if (!NT_STATUS_IS_OK(status)) {
1639 determine if a file can be renamed, or if it is prevented by an
1642 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1643 struct ntvfs_request *req,
1644 struct pvfs_filename *name,
1645 struct odb_lock **lckp)
1649 struct odb_lock *lck;
1650 uint32_t share_access;
1651 uint32_t access_mask;
1652 bool delete_on_close;
1654 status = pvfs_locking_key(name, name, &key);
1655 if (!NT_STATUS_IS_OK(status)) {
1656 return NT_STATUS_NO_MEMORY;
1659 lck = odb_lock(req, pvfs->odb_context, &key);
1661 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1662 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1665 share_access = NTCREATEX_SHARE_ACCESS_READ |
1666 NTCREATEX_SHARE_ACCESS_WRITE;
1667 access_mask = SEC_STD_DELETE;
1668 delete_on_close = false;
1670 status = odb_can_open(lck, name->stream_id,
1671 share_access, access_mask, delete_on_close,
1672 NTCREATEX_DISP_OPEN, false);
1675 * if it's a sharing violation or we got no oplock
1676 * only keep the lock if the caller requested access
1679 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1680 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1686 } else if (!NT_STATUS_IS_OK(status)) {
1699 determine if the file size of a file can be changed,
1700 or if it is prevented by an already open file
1702 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1703 struct ntvfs_request *req,
1704 struct pvfs_filename *name,
1705 struct odb_lock **lckp)
1709 struct odb_lock *lck;
1710 uint32_t share_access;
1711 uint32_t access_mask;
1713 bool delete_on_close;
1715 status = pvfs_locking_key(name, name, &key);
1716 if (!NT_STATUS_IS_OK(status)) {
1717 return NT_STATUS_NO_MEMORY;
1720 lck = odb_lock(req, pvfs->odb_context, &key);
1722 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1723 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1726 share_access = NTCREATEX_SHARE_ACCESS_READ |
1727 NTCREATEX_SHARE_ACCESS_WRITE |
1728 NTCREATEX_SHARE_ACCESS_DELETE;
1730 * I would have thought that we would need to pass
1731 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1733 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1734 * to set the filesize.
1738 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1739 delete_on_close = false;
1740 break_to_none = true;
1742 status = odb_can_open(lck, name->stream_id,
1743 share_access, access_mask, delete_on_close,
1744 NTCREATEX_DISP_OPEN, break_to_none);
1747 * if it's a sharing violation or we got no oplock
1748 * only keep the lock if the caller requested access
1751 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1752 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1758 } else if (!NT_STATUS_IS_OK(status)) {
1771 determine if file meta data can be accessed, or if it is prevented by an
1774 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1775 struct ntvfs_request *req,
1776 struct pvfs_filename *name)
1780 struct odb_lock *lck;
1781 uint32_t share_access;
1782 uint32_t access_mask;
1783 bool delete_on_close;
1785 status = pvfs_locking_key(name, name, &key);
1786 if (!NT_STATUS_IS_OK(status)) {
1787 return NT_STATUS_NO_MEMORY;
1790 lck = odb_lock(req, pvfs->odb_context, &key);
1792 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1793 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1796 share_access = NTCREATEX_SHARE_ACCESS_READ |
1797 NTCREATEX_SHARE_ACCESS_WRITE;
1798 access_mask = SEC_FILE_READ_ATTRIBUTE;
1799 delete_on_close = false;
1801 status = odb_can_open(lck, name->stream_id,
1802 share_access, access_mask, delete_on_close,
1803 NTCREATEX_DISP_OPEN, false);
1805 if (!NT_STATUS_IS_OK(status)) {
1814 determine if delete on close is set on
1816 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1821 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1823 if (!NT_STATUS_IS_OK(status)) {
1824 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1828 return del_on_close;