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->open_completed = false;
267 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
268 pvfs_directory_empty(pvfs, f->handle->name)) {
271 del_on_close = false;
275 /* form the lock context used for opendb locking */
276 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
277 if (!NT_STATUS_IS_OK(status)) {
281 /* get a lock on this file before the actual open */
282 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
284 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
286 /* we were supposed to do a blocking lock, so something
288 return NT_STATUS_INTERNAL_DB_CORRUPTION;
291 /* see if we are allowed to open at the same time as existing opens */
292 status = odb_can_open(lck, name->stream_id,
293 share_access, access_mask, del_on_close,
294 io->generic.in.open_disposition, false);
295 if (!NT_STATUS_IS_OK(status)) {
300 /* now really mark the file as open */
301 status = odb_open_file(lck, f->handle, name->full_name,
302 NULL, false, OPLOCK_NONE, NULL);
304 if (!NT_STATUS_IS_OK(status)) {
309 f->handle->have_opendb_entry = true;
312 DLIST_ADD(pvfs->files.list, f);
314 /* setup destructors to avoid leaks on abnormal termination */
315 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
316 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
319 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
320 mode_t mode = pvfs_fileperms(pvfs, attrib);
322 if (mkdir(name->full_name, mode) == -1) {
323 return pvfs_map_errno(pvfs,errno);
326 pvfs_xattr_unlink_hook(pvfs, name->full_name);
328 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
329 if (!NT_STATUS_IS_OK(status)) {
333 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
334 if (!NT_STATUS_IS_OK(status)) {
338 /* form the lock context used for opendb locking */
339 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
340 if (!NT_STATUS_IS_OK(status)) {
344 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
346 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
348 /* we were supposed to do a blocking lock, so something
350 return NT_STATUS_INTERNAL_DB_CORRUPTION;
353 status = odb_can_open(lck, name->stream_id,
354 share_access, access_mask, del_on_close,
355 io->generic.in.open_disposition, false);
357 if (!NT_STATUS_IS_OK(status)) {
361 status = odb_open_file(lck, f->handle, name->full_name,
362 NULL, false, OPLOCK_NONE, NULL);
364 if (!NT_STATUS_IS_OK(status)) {
368 f->handle->have_opendb_entry = true;
370 create_action = NTCREATEX_ACTION_CREATED;
372 notify_trigger(pvfs->notify_context,
374 FILE_NOTIFY_CHANGE_DIR_NAME,
377 create_action = NTCREATEX_ACTION_EXISTED;
381 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
384 /* the open succeeded, keep this handle permanently */
385 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
386 if (!NT_STATUS_IS_OK(status)) {
390 f->handle->open_completed = true;
392 io->generic.out.oplock_level = OPLOCK_NONE;
393 io->generic.out.file.ntvfs = h;
394 io->generic.out.create_action = create_action;
395 io->generic.out.create_time = name->dos.create_time;
396 io->generic.out.access_time = name->dos.access_time;
397 io->generic.out.write_time = name->dos.write_time;
398 io->generic.out.change_time = name->dos.change_time;
399 io->generic.out.attrib = name->dos.attrib;
400 io->generic.out.alloc_size = name->dos.alloc_size;
401 io->generic.out.size = name->st.st_size;
402 io->generic.out.file_type = FILE_TYPE_DISK;
403 io->generic.out.ipc_state = 0;
404 io->generic.out.is_directory = 1;
409 rmdir(name->full_name);
414 destroy a struct pvfs_file_handle
416 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
418 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
419 h->name->stream_name) {
421 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
422 if (!NT_STATUS_IS_OK(status)) {
423 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
424 h->name->stream_name, h->name->full_name));
429 if (close(h->fd) != 0) {
430 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
431 h->fd, h->name->full_name, strerror(errno)));
436 if (h->have_opendb_entry) {
437 struct odb_lock *lck;
439 const char *delete_path = NULL;
441 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
443 DEBUG(0,("Unable to lock opendb for close\n"));
447 status = odb_close_file(lck, h, &delete_path);
448 if (!NT_STATUS_IS_OK(status)) {
449 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
450 h->name->full_name, nt_errstr(status)));
453 if (h->name->stream_name == NULL &&
454 h->open_completed && delete_path) {
455 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
456 if (!NT_STATUS_IS_OK(status)) {
457 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
458 delete_path, nt_errstr(status)));
460 if (unlink(delete_path) != 0) {
461 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
462 delete_path, strerror(errno)));
464 notify_trigger(h->pvfs->notify_context,
465 NOTIFY_ACTION_REMOVED,
466 FILE_NOTIFY_CHANGE_FILE_NAME,
479 destroy a struct pvfs_file
481 static int pvfs_fnum_destructor(struct pvfs_file *f)
483 DLIST_REMOVE(f->pvfs->files.list, f);
484 pvfs_lock_close(f->pvfs, f);
485 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
492 form the lock context used for byte range locking. This is separate
493 from the locking key used for opendb locking as it needs to take
494 account of file streams (each stream is a separate byte range
497 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
498 struct pvfs_filename *name,
499 struct ntvfs_handle *ntvfs,
500 struct brl_handle **_h)
502 DATA_BLOB odb_key, key;
504 struct brl_handle *h;
506 status = pvfs_locking_key(name, mem_ctx, &odb_key);
507 NT_STATUS_NOT_OK_RETURN(status);
509 if (name->stream_name == NULL) {
512 key = data_blob_talloc(mem_ctx, NULL,
513 odb_key.length + strlen(name->stream_name) + 1);
514 NT_STATUS_HAVE_NO_MEMORY(key.data);
515 memcpy(key.data, odb_key.data, odb_key.length);
516 memcpy(key.data + odb_key.length,
517 name->stream_name, strlen(name->stream_name) + 1);
518 data_blob_free(&odb_key);
521 h = brl_create_handle(mem_ctx, ntvfs, &key);
522 NT_STATUS_HAVE_NO_MEMORY(h);
531 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
532 struct ntvfs_request *req,
533 struct pvfs_filename *name,
538 struct ntvfs_handle *h;
540 struct odb_lock *lck;
541 uint32_t create_options = io->generic.in.create_options;
542 uint32_t share_access = io->generic.in.share_access;
543 uint32_t access_mask = io->generic.in.access_mask;
547 struct pvfs_filename *parent;
548 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
549 bool allow_level_II_oplock = false;
551 if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
552 return NT_STATUS_INVALID_PARAMETER;
555 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
556 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
557 return NT_STATUS_CANNOT_DELETE;
560 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
561 NT_STATUS_NOT_OK_RETURN(status);
563 /* check that the parent isn't opened with delete on close set */
564 status = pvfs_resolve_parent(pvfs, req, name, &parent);
565 if (NT_STATUS_IS_OK(status)) {
566 DATA_BLOB locking_key;
567 status = pvfs_locking_key(parent, req, &locking_key);
568 NT_STATUS_NOT_OK_RETURN(status);
569 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key,
571 NT_STATUS_NOT_OK_RETURN(status);
573 return NT_STATUS_DELETE_PENDING;
577 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
583 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
584 NT_STATUS_NOT_OK_RETURN(status);
586 f = talloc(h, struct pvfs_file);
587 NT_STATUS_HAVE_NO_MEMORY(f);
589 f->handle = talloc(f, struct pvfs_file_handle);
590 NT_STATUS_HAVE_NO_MEMORY(f->handle);
592 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
593 mode = pvfs_fileperms(pvfs, attrib);
595 /* create the file */
596 fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
598 return pvfs_map_errno(pvfs, errno);
601 pvfs_xattr_unlink_hook(pvfs, name->full_name);
603 /* if this was a stream create then create the stream as well */
604 if (name->stream_name) {
605 status = pvfs_stream_create(pvfs, name, fd);
606 if (!NT_STATUS_IS_OK(status)) {
612 /* re-resolve the open fd */
613 status = pvfs_resolve_name_fd(pvfs, fd, name);
614 if (!NT_STATUS_IS_OK(status)) {
619 name->dos.attrib = attrib;
620 status = pvfs_dosattrib_save(pvfs, name, fd);
621 if (!NT_STATUS_IS_OK(status)) {
626 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
627 if (!NT_STATUS_IS_OK(status)) {
631 /* form the lock context used for byte range locking and
633 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
634 if (!NT_STATUS_IS_OK(status)) {
638 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
639 if (!NT_STATUS_IS_OK(status)) {
643 /* grab a lock on the open file record */
644 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
646 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
648 /* we were supposed to do a blocking lock, so something
650 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
654 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
657 del_on_close = false;
660 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
661 oplock_level = OPLOCK_NONE;
662 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
663 oplock_level = OPLOCK_BATCH;
664 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
665 oplock_level = OPLOCK_EXCLUSIVE;
668 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
669 allow_level_II_oplock = true;
672 status = odb_can_open(lck, name->stream_id,
673 share_access, access_mask, del_on_close,
674 io->generic.in.open_disposition, false);
675 if (!NT_STATUS_IS_OK(status)) {
677 /* bad news, we must have hit a race - we don't delete the file
678 here as the most likely scenario is that someone else created
679 the file at the same time */
686 f->pending_list = NULL;
688 f->share_access = io->generic.in.share_access;
689 f->access_mask = access_mask;
690 f->impersonation = io->generic.in.impersonation;
691 f->notify_buffer = NULL;
694 f->handle->pvfs = pvfs;
695 f->handle->name = talloc_steal(f->handle, name);
697 f->handle->create_options = io->generic.in.create_options;
698 f->handle->seek_offset = 0;
699 f->handle->position = 0;
701 f->handle->oplock = NULL;
702 f->handle->have_opendb_entry = true;
703 f->handle->open_completed = false;
705 status = odb_open_file(lck, f->handle, name->full_name,
706 &f->handle->fd, allow_level_II_oplock,
707 oplock_level, &oplock_granted);
709 if (!NT_STATUS_IS_OK(status)) {
710 /* bad news, we must have hit a race - we don't delete the file
711 here as the most likely scenario is that someone else created
712 the file at the same time */
717 DLIST_ADD(pvfs->files.list, f);
719 /* setup a destructor to avoid file descriptor leaks on
720 abnormal termination */
721 talloc_set_destructor(f, pvfs_fnum_destructor);
722 talloc_set_destructor(f->handle, pvfs_handle_destructor);
724 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
725 oplock_granted = OPLOCK_BATCH;
726 } else if (oplock_granted != OPLOCK_NONE) {
727 status = pvfs_setup_oplock(f, oplock_granted);
728 if (!NT_STATUS_IS_OK(status)) {
733 io->generic.out.oplock_level = oplock_granted;
734 io->generic.out.file.ntvfs = f->ntvfs;
735 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
736 io->generic.out.create_time = name->dos.create_time;
737 io->generic.out.access_time = name->dos.access_time;
738 io->generic.out.write_time = name->dos.write_time;
739 io->generic.out.change_time = name->dos.change_time;
740 io->generic.out.attrib = name->dos.attrib;
741 io->generic.out.alloc_size = name->dos.alloc_size;
742 io->generic.out.size = name->st.st_size;
743 io->generic.out.file_type = FILE_TYPE_DISK;
744 io->generic.out.ipc_state = 0;
745 io->generic.out.is_directory = 0;
747 /* success - keep the file handle */
748 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
749 if (!NT_STATUS_IS_OK(status)) {
753 f->handle->open_completed = true;
755 notify_trigger(pvfs->notify_context,
757 FILE_NOTIFY_CHANGE_FILE_NAME,
764 unlink(name->full_name);
769 state of a pending retry
771 struct pvfs_odb_retry {
772 struct ntvfs_module_context *ntvfs;
773 struct ntvfs_request *req;
774 DATA_BLOB odb_locking_key;
777 void (*callback)(struct pvfs_odb_retry *r,
778 struct ntvfs_module_context *ntvfs,
779 struct ntvfs_request *req,
782 enum pvfs_wait_notice reason);
785 /* destroy a pending request */
786 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
788 struct pvfs_state *pvfs = r->ntvfs->private_data;
789 if (r->odb_locking_key.data) {
790 struct odb_lock *lck;
791 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
793 odb_remove_pending(lck, r);
800 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
802 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
804 if (reason == PVFS_WAIT_EVENT) {
806 * The pending odb entry is already removed.
807 * We use a null locking key to indicate this
810 data_blob_free(&r->odb_locking_key);
813 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
817 setup for a retry of a request that was rejected
820 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
821 struct ntvfs_request *req,
822 struct odb_lock *lck,
823 struct timeval end_time,
826 void (*callback)(struct pvfs_odb_retry *r,
827 struct ntvfs_module_context *ntvfs,
828 struct ntvfs_request *req,
831 enum pvfs_wait_notice reason))
833 struct pvfs_state *pvfs = ntvfs->private_data;
834 struct pvfs_odb_retry *r;
835 struct pvfs_wait *wait_handle;
838 r = talloc(req, struct pvfs_odb_retry);
839 NT_STATUS_HAVE_NO_MEMORY(r);
844 r->private_data = private_data;
845 r->callback = callback;
846 r->odb_locking_key = odb_get_key(r, lck);
847 if (r->odb_locking_key.data == NULL) {
848 return NT_STATUS_NO_MEMORY;
851 /* setup a pending lock */
852 status = odb_open_file_pending(lck, r);
853 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
855 * maybe only a unix application
858 data_blob_free(&r->odb_locking_key);
859 } else if (!NT_STATUS_IS_OK(status)) {
865 talloc_set_destructor(r, pvfs_odb_retry_destructor);
867 wait_handle = pvfs_wait_message(pvfs, req,
868 MSG_PVFS_RETRY_OPEN, end_time,
869 pvfs_odb_retry_callback, r);
870 if (wait_handle == NULL) {
871 return NT_STATUS_NO_MEMORY;
874 talloc_steal(r, wait_handle);
880 retry an open after a sharing violation
882 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
883 struct ntvfs_module_context *ntvfs,
884 struct ntvfs_request *req,
887 enum pvfs_wait_notice reason)
889 union smb_open *io = talloc_get_type(_io, union smb_open);
890 struct timeval *final_timeout = NULL;
894 final_timeout = talloc_get_type(private_data,
898 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
899 just a bug in their server, but we better do the same */
900 if (reason == PVFS_WAIT_CANCEL) {
904 if (reason == PVFS_WAIT_TIMEOUT) {
906 !timeval_expired(final_timeout)) {
908 * we need to retry periodictly
909 * after an EAGAIN as there's
910 * no way the kernel tell us
911 * an oplock is released.
915 /* if it timed out, then give the failure
918 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
919 req->async_states->send_fn(req);
926 /* try the open again, which could trigger another retry setup
927 if it wants to, so we have to unmark the async flag so we
928 will know if it does a second async reply */
929 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
931 status = pvfs_open(ntvfs, req, io);
932 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
933 /* the 2nd try also replied async, so we don't send
938 /* re-mark it async, just in case someone up the chain does
940 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
942 /* send the reply up the chain */
943 req->async_states->status = status;
944 req->async_states->send_fn(req);
949 special handling for openx DENY_DOS semantics
951 This function attempts a reference open using an existing handle. If its allowed,
952 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
953 open processing continues.
955 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
956 struct ntvfs_request *req, union smb_open *io,
957 struct pvfs_file *f, struct odb_lock *lck)
959 struct pvfs_state *pvfs = ntvfs->private_data;
960 struct pvfs_file *f2;
961 struct pvfs_filename *name;
964 /* search for an existing open with the right parameters. Note
965 the magic ntcreatex options flag, which is set in the
966 generic mapping code. This might look ugly, but its
967 actually pretty much now w2k does it internally as well.
969 If you look at the BASE-DENYDOS test you will see that a
970 DENY_DOS is a very special case, and in the right
971 circumstances you actually get the _same_ handle back
972 twice, rather than a new handle.
974 for (f2=pvfs->files.list;f2;f2=f2->next) {
976 f2->ntvfs->session_info == req->session_info &&
977 f2->ntvfs->smbpid == req->smbpid &&
978 (f2->handle->create_options &
979 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
980 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
981 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
982 strcasecmp_m(f2->handle->name->original_name,
983 io->generic.in.fname)==0) {
989 return NT_STATUS_SHARING_VIOLATION;
992 /* quite an insane set of semantics ... */
993 if (is_exe_filename(io->generic.in.fname) &&
994 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
995 return NT_STATUS_SHARING_VIOLATION;
999 setup a reference to the existing handle
1001 talloc_free(f->handle);
1002 f->handle = talloc_reference(f, f2->handle);
1006 name = f->handle->name;
1008 io->generic.out.oplock_level = OPLOCK_NONE;
1009 io->generic.out.file.ntvfs = f->ntvfs;
1010 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1011 io->generic.out.create_time = name->dos.create_time;
1012 io->generic.out.access_time = name->dos.access_time;
1013 io->generic.out.write_time = name->dos.write_time;
1014 io->generic.out.change_time = name->dos.change_time;
1015 io->generic.out.attrib = name->dos.attrib;
1016 io->generic.out.alloc_size = name->dos.alloc_size;
1017 io->generic.out.size = name->st.st_size;
1018 io->generic.out.file_type = FILE_TYPE_DISK;
1019 io->generic.out.ipc_state = 0;
1020 io->generic.out.is_directory = 0;
1022 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1023 NT_STATUS_NOT_OK_RETURN(status);
1025 return NT_STATUS_OK;
1031 setup for a open retry after a sharing violation
1033 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1034 struct ntvfs_request *req,
1036 struct pvfs_file *f,
1037 struct odb_lock *lck,
1038 NTSTATUS parent_status)
1040 struct pvfs_state *pvfs = ntvfs->private_data;
1042 struct timeval end_time;
1043 struct timeval *final_timeout = NULL;
1045 if (io->generic.in.create_options &
1046 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1047 /* see if we can satisfy the request using the special DENY_DOS
1049 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1050 if (NT_STATUS_IS_OK(status)) {
1055 /* the retry should allocate a new file handle */
1058 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1059 end_time = timeval_add(&req->statistics.request_time,
1060 0, pvfs->sharing_violation_delay);
1061 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1062 end_time = timeval_add(&req->statistics.request_time,
1063 pvfs->oplock_break_timeout, 0);
1064 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1066 * we got EAGAIN which means a unix application
1067 * has an oplock or share mode
1069 * we retry every 4/5 of the sharing violation delay
1070 * to see if the unix application
1071 * has released the oplock or share mode.
1073 final_timeout = talloc(req, struct timeval);
1074 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1075 *final_timeout = timeval_add(&req->statistics.request_time,
1076 pvfs->oplock_break_timeout,
1078 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1079 end_time = timeval_min(final_timeout, &end_time);
1081 return NT_STATUS_INTERNAL_ERROR;
1084 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1085 final_timeout, pvfs_retry_open_sharing);
1091 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1092 struct ntvfs_request *req, union smb_open *io)
1094 struct pvfs_state *pvfs = ntvfs->private_data;
1096 struct pvfs_filename *name;
1097 struct pvfs_file *f;
1098 struct ntvfs_handle *h;
1101 struct odb_lock *lck;
1102 uint32_t create_options;
1103 uint32_t share_access;
1104 uint32_t access_mask;
1106 bool stream_existed, stream_truncate=false;
1107 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1108 bool allow_level_II_oplock = false;
1110 /* use the generic mapping code to avoid implementing all the
1111 different open calls. */
1112 if (io->generic.level != RAW_OPEN_GENERIC &&
1113 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1114 return ntvfs_map_open(ntvfs, req, io);
1117 /* resolve the cifs name to a posix name */
1118 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1119 PVFS_RESOLVE_STREAMS, &name);
1120 if (!NT_STATUS_IS_OK(status)) {
1124 /* if the client specified that it must not be a directory then
1125 check that it isn't */
1126 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1127 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1128 return NT_STATUS_FILE_IS_A_DIRECTORY;
1131 /* if the client specified that it must be a directory then
1133 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1134 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1135 return NT_STATUS_NOT_A_DIRECTORY;
1138 /* directory opens are handled separately */
1139 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1140 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1141 return pvfs_open_directory(pvfs, req, name, io);
1144 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1145 open doesn't match */
1146 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1148 create_options = io->generic.in.create_options;
1149 share_access = io->generic.in.share_access;
1150 access_mask = io->generic.in.access_mask;
1152 /* certain create options are not allowed */
1153 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1154 !(access_mask & SEC_STD_DELETE)) {
1155 return NT_STATUS_INVALID_PARAMETER;
1160 switch (io->generic.in.open_disposition) {
1161 case NTCREATEX_DISP_SUPERSEDE:
1162 case NTCREATEX_DISP_OVERWRITE_IF:
1163 if (name->stream_name == NULL) {
1166 stream_truncate = true;
1170 case NTCREATEX_DISP_OPEN:
1171 if (!name->stream_exists) {
1172 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1177 case NTCREATEX_DISP_OVERWRITE:
1178 if (!name->stream_exists) {
1179 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1181 if (name->stream_name == NULL) {
1184 stream_truncate = true;
1188 case NTCREATEX_DISP_CREATE:
1189 if (name->stream_exists) {
1190 return NT_STATUS_OBJECT_NAME_COLLISION;
1195 case NTCREATEX_DISP_OPEN_IF:
1200 return NT_STATUS_INVALID_PARAMETER;
1203 /* handle creating a new file separately */
1204 if (!name->exists) {
1205 status = pvfs_create_file(pvfs, req, name, io);
1206 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1210 /* we've hit a race - the file was created during this call */
1211 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1215 /* try re-resolving the name */
1216 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1217 if (!NT_STATUS_IS_OK(status)) {
1220 /* fall through to a normal open */
1223 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1224 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1225 return NT_STATUS_CANNOT_DELETE;
1228 /* check the security descriptor */
1229 status = pvfs_access_check(pvfs, req, name, &access_mask);
1230 if (!NT_STATUS_IS_OK(status)) {
1234 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1235 NT_STATUS_NOT_OK_RETURN(status);
1237 f = talloc(h, struct pvfs_file);
1239 return NT_STATUS_NO_MEMORY;
1242 f->handle = talloc(f, struct pvfs_file_handle);
1243 if (f->handle == NULL) {
1244 return NT_STATUS_NO_MEMORY;
1249 f->pending_list = NULL;
1251 f->share_access = io->generic.in.share_access;
1252 f->access_mask = access_mask;
1253 f->impersonation = io->generic.in.impersonation;
1254 f->notify_buffer = NULL;
1257 f->handle->pvfs = pvfs;
1259 f->handle->name = talloc_steal(f->handle, name);
1260 f->handle->create_options = io->generic.in.create_options;
1261 f->handle->seek_offset = 0;
1262 f->handle->position = 0;
1263 f->handle->mode = 0;
1264 f->handle->oplock = NULL;
1265 f->handle->have_opendb_entry = false;
1266 f->handle->open_completed = false;
1268 /* form the lock context used for byte range locking and
1270 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1271 if (!NT_STATUS_IS_OK(status)) {
1275 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1276 if (!NT_STATUS_IS_OK(status)) {
1280 /* get a lock on this file before the actual open */
1281 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1283 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1285 /* we were supposed to do a blocking lock, so something
1287 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1290 DLIST_ADD(pvfs->files.list, f);
1292 /* setup a destructor to avoid file descriptor leaks on
1293 abnormal termination */
1294 talloc_set_destructor(f, pvfs_fnum_destructor);
1295 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1298 * Only SMB2 takes care of the delete_on_close,
1301 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1302 req->ctx->protocol == PROTOCOL_SMB2) {
1303 del_on_close = true;
1305 del_on_close = false;
1308 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1309 oplock_level = OPLOCK_NONE;
1310 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1311 oplock_level = OPLOCK_BATCH;
1312 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1313 oplock_level = OPLOCK_EXCLUSIVE;
1316 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1317 allow_level_II_oplock = true;
1320 /* see if we are allowed to open at the same time as existing opens */
1321 status = odb_can_open(lck, name->stream_id,
1322 share_access, access_mask, del_on_close,
1323 io->generic.in.open_disposition, false);
1326 * on a sharing violation we need to retry when the file is closed by
1327 * the other user, or after 1 second
1328 * on a non granted oplock we need to retry when the file is closed by
1329 * the other user, or after 30 seconds
1331 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1332 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1333 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1334 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1337 if (!NT_STATUS_IS_OK(status)) {
1342 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1348 /* do the actual open */
1349 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1351 status = pvfs_map_errno(f->pvfs, errno);
1354 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1356 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1357 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1358 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1367 /* now really mark the file as open */
1368 status = odb_open_file(lck, f->handle, name->full_name,
1369 &f->handle->fd, allow_level_II_oplock,
1370 oplock_level, &oplock_granted);
1372 if (!NT_STATUS_IS_OK(status)) {
1377 f->handle->have_opendb_entry = true;
1379 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1380 oplock_granted = OPLOCK_BATCH;
1381 } else if (oplock_granted != OPLOCK_NONE) {
1382 status = pvfs_setup_oplock(f, oplock_granted);
1383 if (!NT_STATUS_IS_OK(status)) {
1389 stream_existed = name->stream_exists;
1391 /* if this was a stream create then create the stream as well */
1392 if (!name->stream_exists) {
1393 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1394 if (!NT_STATUS_IS_OK(status)) {
1398 if (stream_truncate) {
1399 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1400 if (!NT_STATUS_IS_OK(status)) {
1407 /* re-resolve the open fd */
1408 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1409 if (!NT_STATUS_IS_OK(status)) {
1414 if (f->handle->name->stream_id == 0 &&
1415 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1416 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1417 /* for overwrite we need to replace file permissions */
1418 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1419 mode_t mode = pvfs_fileperms(pvfs, attrib);
1420 if (fchmod(fd, mode) == -1) {
1422 return pvfs_map_errno(pvfs, errno);
1424 name->dos.attrib = attrib;
1425 status = pvfs_dosattrib_save(pvfs, name, fd);
1426 if (!NT_STATUS_IS_OK(status)) {
1434 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1435 NT_STATUS_NOT_OK_RETURN(status);
1437 /* mark the open as having completed fully, so delete on close
1439 f->handle->open_completed = true;
1441 io->generic.out.oplock_level = oplock_granted;
1442 io->generic.out.file.ntvfs = h;
1443 io->generic.out.create_action = stream_existed?
1444 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1445 io->generic.out.create_time = name->dos.create_time;
1446 io->generic.out.access_time = name->dos.access_time;
1447 io->generic.out.write_time = name->dos.write_time;
1448 io->generic.out.change_time = name->dos.change_time;
1449 io->generic.out.attrib = name->dos.attrib;
1450 io->generic.out.alloc_size = name->dos.alloc_size;
1451 io->generic.out.size = name->st.st_size;
1452 io->generic.out.file_type = FILE_TYPE_DISK;
1453 io->generic.out.ipc_state = 0;
1454 io->generic.out.is_directory = 0;
1456 return NT_STATUS_OK;
1463 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1464 struct ntvfs_request *req, union smb_close *io)
1466 struct pvfs_state *pvfs = ntvfs->private_data;
1467 struct pvfs_file *f;
1468 struct utimbuf unix_times;
1470 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1471 return NT_STATUS_DOS(ERRSRV, ERRerror);
1474 if (io->generic.level != RAW_CLOSE_CLOSE) {
1475 return ntvfs_map_close(ntvfs, req, io);
1478 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1480 return NT_STATUS_INVALID_HANDLE;
1483 if (!null_time(io->close.in.write_time)) {
1484 unix_times.actime = 0;
1485 unix_times.modtime = io->close.in.write_time;
1486 utime(f->handle->name->full_name, &unix_times);
1491 return NT_STATUS_OK;
1496 logoff - close all file descriptors open by a vuid
1498 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1499 struct ntvfs_request *req)
1501 struct pvfs_state *pvfs = ntvfs->private_data;
1502 struct pvfs_file *f, *next;
1504 for (f=pvfs->files.list;f;f=next) {
1506 if (f->ntvfs->session_info == req->session_info) {
1511 return NT_STATUS_OK;
1516 exit - close files for the current pid
1518 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1519 struct ntvfs_request *req)
1521 struct pvfs_state *pvfs = ntvfs->private_data;
1522 struct pvfs_file *f, *next;
1524 for (f=pvfs->files.list;f;f=next) {
1526 if (f->ntvfs->session_info == req->session_info &&
1527 f->ntvfs->smbpid == req->smbpid) {
1532 return NT_STATUS_OK;
1537 change the delete on close flag on an already open file
1539 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1540 struct ntvfs_request *req,
1541 struct pvfs_file *f, bool del_on_close)
1543 struct odb_lock *lck;
1546 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1547 return NT_STATUS_CANNOT_DELETE;
1550 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1551 !pvfs_directory_empty(pvfs, f->handle->name)) {
1552 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1556 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1558 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1561 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1563 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1566 status = odb_set_delete_on_close(lck, del_on_close);
1575 determine if a file can be deleted, or if it is prevented by an
1578 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1579 struct ntvfs_request *req,
1580 struct pvfs_filename *name,
1581 struct odb_lock **lckp)
1585 struct odb_lock *lck;
1586 uint32_t share_access;
1587 uint32_t access_mask;
1588 bool delete_on_close;
1590 status = pvfs_locking_key(name, name, &key);
1591 if (!NT_STATUS_IS_OK(status)) {
1592 return NT_STATUS_NO_MEMORY;
1595 lck = odb_lock(req, pvfs->odb_context, &key);
1597 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1598 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1601 share_access = NTCREATEX_SHARE_ACCESS_READ |
1602 NTCREATEX_SHARE_ACCESS_WRITE |
1603 NTCREATEX_SHARE_ACCESS_DELETE;
1604 access_mask = SEC_STD_DELETE;
1605 delete_on_close = true;
1607 status = odb_can_open(lck, name->stream_id,
1608 share_access, access_mask, delete_on_close,
1609 NTCREATEX_DISP_OPEN, false);
1611 if (NT_STATUS_IS_OK(status)) {
1612 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1616 * if it's a sharing violation or we got no oplock
1617 * only keep the lock if the caller requested access
1620 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1621 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1627 } else if (!NT_STATUS_IS_OK(status)) {
1640 determine if a file can be renamed, or if it is prevented by an
1643 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1644 struct ntvfs_request *req,
1645 struct pvfs_filename *name,
1646 struct odb_lock **lckp)
1650 struct odb_lock *lck;
1651 uint32_t share_access;
1652 uint32_t access_mask;
1653 bool delete_on_close;
1655 status = pvfs_locking_key(name, name, &key);
1656 if (!NT_STATUS_IS_OK(status)) {
1657 return NT_STATUS_NO_MEMORY;
1660 lck = odb_lock(req, pvfs->odb_context, &key);
1662 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1663 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1666 share_access = NTCREATEX_SHARE_ACCESS_READ |
1667 NTCREATEX_SHARE_ACCESS_WRITE;
1668 access_mask = SEC_STD_DELETE;
1669 delete_on_close = false;
1671 status = odb_can_open(lck, name->stream_id,
1672 share_access, access_mask, delete_on_close,
1673 NTCREATEX_DISP_OPEN, false);
1676 * if it's a sharing violation or we got no oplock
1677 * only keep the lock if the caller requested access
1680 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1681 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1687 } else if (!NT_STATUS_IS_OK(status)) {
1700 determine if the file size of a file can be changed,
1701 or if it is prevented by an already open file
1703 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1704 struct ntvfs_request *req,
1705 struct pvfs_filename *name,
1706 struct odb_lock **lckp)
1710 struct odb_lock *lck;
1711 uint32_t share_access;
1712 uint32_t access_mask;
1714 bool delete_on_close;
1716 status = pvfs_locking_key(name, name, &key);
1717 if (!NT_STATUS_IS_OK(status)) {
1718 return NT_STATUS_NO_MEMORY;
1721 lck = odb_lock(req, pvfs->odb_context, &key);
1723 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1724 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1727 share_access = NTCREATEX_SHARE_ACCESS_READ |
1728 NTCREATEX_SHARE_ACCESS_WRITE |
1729 NTCREATEX_SHARE_ACCESS_DELETE;
1731 * I would have thought that we would need to pass
1732 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1734 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1735 * to set the filesize.
1739 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1740 delete_on_close = false;
1741 break_to_none = true;
1743 status = odb_can_open(lck, name->stream_id,
1744 share_access, access_mask, delete_on_close,
1745 NTCREATEX_DISP_OPEN, break_to_none);
1748 * if it's a sharing violation or we got no oplock
1749 * only keep the lock if the caller requested access
1752 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1753 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1759 } else if (!NT_STATUS_IS_OK(status)) {
1772 determine if file meta data can be accessed, or if it is prevented by an
1775 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1776 struct ntvfs_request *req,
1777 struct pvfs_filename *name)
1781 struct odb_lock *lck;
1782 uint32_t share_access;
1783 uint32_t access_mask;
1784 bool delete_on_close;
1786 status = pvfs_locking_key(name, name, &key);
1787 if (!NT_STATUS_IS_OK(status)) {
1788 return NT_STATUS_NO_MEMORY;
1791 lck = odb_lock(req, pvfs->odb_context, &key);
1793 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1794 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1797 share_access = NTCREATEX_SHARE_ACCESS_READ |
1798 NTCREATEX_SHARE_ACCESS_WRITE;
1799 access_mask = SEC_FILE_READ_ATTRIBUTE;
1800 delete_on_close = false;
1802 status = odb_can_open(lck, name->stream_id,
1803 share_access, access_mask, delete_on_close,
1804 NTCREATEX_DISP_OPEN, false);
1806 if (!NT_STATUS_IS_OK(status)) {
1815 determine if delete on close is set on
1817 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1822 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1824 if (!NT_STATUS_IS_OK(status)) {
1825 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1829 return del_on_close;