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;
187 create_options = io->generic.in.create_options;
188 share_access = io->generic.in.share_access;
190 forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false;
192 if (name->stream_name) {
194 return NT_STATUS_NOT_A_DIRECTORY;
196 return NT_STATUS_FILE_IS_A_DIRECTORY;
200 /* if the client says it must be a directory, and it isn't,
202 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
203 return NT_STATUS_NOT_A_DIRECTORY;
206 switch (io->generic.in.open_disposition) {
207 case NTCREATEX_DISP_OPEN_IF:
210 case NTCREATEX_DISP_OPEN:
212 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
216 case NTCREATEX_DISP_CREATE:
218 return NT_STATUS_OBJECT_NAME_COLLISION;
222 case NTCREATEX_DISP_OVERWRITE_IF:
223 case NTCREATEX_DISP_OVERWRITE:
224 case NTCREATEX_DISP_SUPERSEDE:
226 return NT_STATUS_INVALID_PARAMETER;
229 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
230 NT_STATUS_NOT_OK_RETURN(status);
232 f = talloc(h, struct pvfs_file);
234 return NT_STATUS_NO_MEMORY;
237 f->handle = talloc(f, struct pvfs_file_handle);
238 if (f->handle == NULL) {
239 return NT_STATUS_NO_MEMORY;
243 /* check the security descriptor */
244 status = pvfs_access_check(pvfs, req, name, &access_mask);
246 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
248 if (!NT_STATUS_IS_OK(status)) {
254 f->pending_list = NULL;
256 f->share_access = io->generic.in.share_access;
257 f->impersonation = io->generic.in.impersonation;
258 f->access_mask = access_mask;
259 f->brl_handle = NULL;
260 f->notify_buffer = NULL;
263 f->handle->pvfs = pvfs;
264 f->handle->name = talloc_steal(f->handle, name);
266 f->handle->odb_locking_key = data_blob(NULL, 0);
267 f->handle->create_options = io->generic.in.create_options;
268 f->handle->seek_offset = 0;
269 f->handle->position = 0;
271 f->handle->oplock = NULL;
272 f->handle->open_completed = false;
274 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
275 pvfs_directory_empty(pvfs, f->handle->name)) {
278 del_on_close = false;
282 /* form the lock context used for opendb locking */
283 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
284 if (!NT_STATUS_IS_OK(status)) {
288 /* get a lock on this file before the actual open */
289 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
291 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
293 /* we were supposed to do a blocking lock, so something
295 return NT_STATUS_INTERNAL_DB_CORRUPTION;
298 /* see if we are allowed to open at the same time as existing opens */
299 status = odb_can_open(lck, name->stream_id,
300 share_access, access_mask, del_on_close,
301 io->generic.in.open_disposition, false);
302 if (!NT_STATUS_IS_OK(status)) {
307 /* now really mark the file as open */
308 status = odb_open_file(lck, f->handle, name->full_name,
309 NULL, false, OPLOCK_NONE, NULL);
311 if (!NT_STATUS_IS_OK(status)) {
316 f->handle->have_opendb_entry = true;
319 DLIST_ADD(pvfs->files.list, f);
321 /* setup destructors to avoid leaks on abnormal termination */
322 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
323 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
326 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
327 mode_t mode = pvfs_fileperms(pvfs, attrib);
329 if (mkdir(name->full_name, mode) == -1) {
330 return pvfs_map_errno(pvfs,errno);
333 pvfs_xattr_unlink_hook(pvfs, name->full_name);
335 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
336 if (!NT_STATUS_IS_OK(status)) {
340 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
341 if (!NT_STATUS_IS_OK(status)) {
345 /* form the lock context used for opendb locking */
346 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
347 if (!NT_STATUS_IS_OK(status)) {
351 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
353 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
355 /* we were supposed to do a blocking lock, so something
357 return NT_STATUS_INTERNAL_DB_CORRUPTION;
360 status = odb_can_open(lck, name->stream_id,
361 share_access, access_mask, del_on_close,
362 io->generic.in.open_disposition, false);
364 if (!NT_STATUS_IS_OK(status)) {
368 status = odb_open_file(lck, f->handle, name->full_name,
369 NULL, false, OPLOCK_NONE, NULL);
371 if (!NT_STATUS_IS_OK(status)) {
375 f->handle->have_opendb_entry = true;
377 create_action = NTCREATEX_ACTION_CREATED;
379 notify_trigger(pvfs->notify_context,
381 FILE_NOTIFY_CHANGE_DIR_NAME,
384 create_action = NTCREATEX_ACTION_EXISTED;
388 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
391 /* the open succeeded, keep this handle permanently */
392 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
393 if (!NT_STATUS_IS_OK(status)) {
397 f->handle->open_completed = true;
399 io->generic.out.oplock_level = OPLOCK_NONE;
400 io->generic.out.file.ntvfs = h;
401 io->generic.out.create_action = create_action;
402 io->generic.out.create_time = name->dos.create_time;
403 io->generic.out.access_time = name->dos.access_time;
404 io->generic.out.write_time = name->dos.write_time;
405 io->generic.out.change_time = name->dos.change_time;
406 io->generic.out.attrib = name->dos.attrib;
407 io->generic.out.alloc_size = name->dos.alloc_size;
408 io->generic.out.size = name->st.st_size;
409 io->generic.out.file_type = FILE_TYPE_DISK;
410 io->generic.out.ipc_state = 0;
411 io->generic.out.is_directory = 1;
416 rmdir(name->full_name);
421 destroy a struct pvfs_file_handle
423 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
425 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
426 h->name->stream_name) {
428 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
429 if (!NT_STATUS_IS_OK(status)) {
430 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
431 h->name->stream_name, h->name->full_name));
436 if (close(h->fd) != 0) {
437 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
438 h->fd, h->name->full_name, strerror(errno)));
443 if (h->have_opendb_entry) {
444 struct odb_lock *lck;
446 const char *delete_path = NULL;
448 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
450 DEBUG(0,("Unable to lock opendb for close\n"));
454 status = odb_close_file(lck, h, &delete_path);
455 if (!NT_STATUS_IS_OK(status)) {
456 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
457 h->name->full_name, nt_errstr(status)));
460 if (h->name->stream_name == NULL &&
461 h->open_completed && delete_path) {
462 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
463 if (!NT_STATUS_IS_OK(status)) {
464 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
465 delete_path, nt_errstr(status)));
467 if (unlink(delete_path) != 0) {
468 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
469 delete_path, strerror(errno)));
471 notify_trigger(h->pvfs->notify_context,
472 NOTIFY_ACTION_REMOVED,
473 FILE_NOTIFY_CHANGE_FILE_NAME,
486 destroy a struct pvfs_file
488 static int pvfs_fnum_destructor(struct pvfs_file *f)
490 DLIST_REMOVE(f->pvfs->files.list, f);
491 pvfs_lock_close(f->pvfs, f);
492 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
499 form the lock context used for byte range locking. This is separate
500 from the locking key used for opendb locking as it needs to take
501 account of file streams (each stream is a separate byte range
504 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
505 struct pvfs_filename *name,
506 struct ntvfs_handle *ntvfs,
507 struct brl_handle **_h)
509 DATA_BLOB odb_key, key;
511 struct brl_handle *h;
513 status = pvfs_locking_key(name, mem_ctx, &odb_key);
514 NT_STATUS_NOT_OK_RETURN(status);
516 if (name->stream_name == NULL) {
519 key = data_blob_talloc(mem_ctx, NULL,
520 odb_key.length + strlen(name->stream_name) + 1);
521 NT_STATUS_HAVE_NO_MEMORY(key.data);
522 memcpy(key.data, odb_key.data, odb_key.length);
523 memcpy(key.data + odb_key.length,
524 name->stream_name, strlen(name->stream_name) + 1);
525 data_blob_free(&odb_key);
528 h = brl_create_handle(mem_ctx, ntvfs, &key);
529 NT_STATUS_HAVE_NO_MEMORY(h);
538 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
539 struct ntvfs_request *req,
540 struct pvfs_filename *name,
545 struct ntvfs_handle *h;
547 struct odb_lock *lck;
548 uint32_t create_options = io->generic.in.create_options;
549 uint32_t share_access = io->generic.in.share_access;
550 uint32_t access_mask = io->generic.in.access_mask;
554 struct pvfs_filename *parent;
555 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
556 bool allow_level_II_oplock = false;
558 if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
559 return NT_STATUS_INVALID_PARAMETER;
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->open_completed = false;
712 status = odb_open_file(lck, f->handle, name->full_name,
713 &f->handle->fd, allow_level_II_oplock,
714 oplock_level, &oplock_granted);
716 if (!NT_STATUS_IS_OK(status)) {
717 /* bad news, we must have hit a race - we don't delete the file
718 here as the most likely scenario is that someone else created
719 the file at the same time */
724 DLIST_ADD(pvfs->files.list, f);
726 /* setup a destructor to avoid file descriptor leaks on
727 abnormal termination */
728 talloc_set_destructor(f, pvfs_fnum_destructor);
729 talloc_set_destructor(f->handle, pvfs_handle_destructor);
731 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
732 oplock_granted = OPLOCK_BATCH;
733 } else if (oplock_granted != OPLOCK_NONE) {
734 status = pvfs_setup_oplock(f, oplock_granted);
735 if (!NT_STATUS_IS_OK(status)) {
740 io->generic.out.oplock_level = oplock_granted;
741 io->generic.out.file.ntvfs = f->ntvfs;
742 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
743 io->generic.out.create_time = name->dos.create_time;
744 io->generic.out.access_time = name->dos.access_time;
745 io->generic.out.write_time = name->dos.write_time;
746 io->generic.out.change_time = name->dos.change_time;
747 io->generic.out.attrib = name->dos.attrib;
748 io->generic.out.alloc_size = name->dos.alloc_size;
749 io->generic.out.size = name->st.st_size;
750 io->generic.out.file_type = FILE_TYPE_DISK;
751 io->generic.out.ipc_state = 0;
752 io->generic.out.is_directory = 0;
754 /* success - keep the file handle */
755 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
756 if (!NT_STATUS_IS_OK(status)) {
760 f->handle->open_completed = true;
762 notify_trigger(pvfs->notify_context,
764 FILE_NOTIFY_CHANGE_FILE_NAME,
771 unlink(name->full_name);
776 state of a pending retry
778 struct pvfs_odb_retry {
779 struct ntvfs_module_context *ntvfs;
780 struct ntvfs_request *req;
781 DATA_BLOB odb_locking_key;
784 void (*callback)(struct pvfs_odb_retry *r,
785 struct ntvfs_module_context *ntvfs,
786 struct ntvfs_request *req,
789 enum pvfs_wait_notice reason);
792 /* destroy a pending request */
793 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
795 struct pvfs_state *pvfs = r->ntvfs->private_data;
796 if (r->odb_locking_key.data) {
797 struct odb_lock *lck;
798 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
800 odb_remove_pending(lck, r);
807 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
809 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
811 if (reason == PVFS_WAIT_EVENT) {
813 * The pending odb entry is already removed.
814 * We use a null locking key to indicate this
817 data_blob_free(&r->odb_locking_key);
820 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
824 setup for a retry of a request that was rejected
827 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
828 struct ntvfs_request *req,
829 struct odb_lock *lck,
830 struct timeval end_time,
833 void (*callback)(struct pvfs_odb_retry *r,
834 struct ntvfs_module_context *ntvfs,
835 struct ntvfs_request *req,
838 enum pvfs_wait_notice reason))
840 struct pvfs_state *pvfs = ntvfs->private_data;
841 struct pvfs_odb_retry *r;
842 struct pvfs_wait *wait_handle;
845 r = talloc(req, struct pvfs_odb_retry);
846 NT_STATUS_HAVE_NO_MEMORY(r);
851 r->private_data = private_data;
852 r->callback = callback;
853 r->odb_locking_key = odb_get_key(r, lck);
854 if (r->odb_locking_key.data == NULL) {
855 return NT_STATUS_NO_MEMORY;
858 /* setup a pending lock */
859 status = odb_open_file_pending(lck, r);
860 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
862 * maybe only a unix application
865 data_blob_free(&r->odb_locking_key);
866 } else if (!NT_STATUS_IS_OK(status)) {
872 talloc_set_destructor(r, pvfs_odb_retry_destructor);
874 wait_handle = pvfs_wait_message(pvfs, req,
875 MSG_PVFS_RETRY_OPEN, end_time,
876 pvfs_odb_retry_callback, r);
877 if (wait_handle == NULL) {
878 return NT_STATUS_NO_MEMORY;
881 talloc_steal(r, wait_handle);
887 retry an open after a sharing violation
889 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
890 struct ntvfs_module_context *ntvfs,
891 struct ntvfs_request *req,
894 enum pvfs_wait_notice reason)
896 union smb_open *io = talloc_get_type(_io, union smb_open);
897 struct timeval *final_timeout = NULL;
901 final_timeout = talloc_get_type(private_data,
905 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
906 just a bug in their server, but we better do the same */
907 if (reason == PVFS_WAIT_CANCEL) {
911 if (reason == PVFS_WAIT_TIMEOUT) {
913 !timeval_expired(final_timeout)) {
915 * we need to retry periodictly
916 * after an EAGAIN as there's
917 * no way the kernel tell us
918 * an oplock is released.
922 /* if it timed out, then give the failure
925 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
926 req->async_states->send_fn(req);
933 /* try the open again, which could trigger another retry setup
934 if it wants to, so we have to unmark the async flag so we
935 will know if it does a second async reply */
936 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
938 status = pvfs_open(ntvfs, req, io);
939 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
940 /* the 2nd try also replied async, so we don't send
945 /* re-mark it async, just in case someone up the chain does
947 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
949 /* send the reply up the chain */
950 req->async_states->status = status;
951 req->async_states->send_fn(req);
956 special handling for openx DENY_DOS semantics
958 This function attempts a reference open using an existing handle. If its allowed,
959 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
960 open processing continues.
962 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
963 struct ntvfs_request *req, union smb_open *io,
964 struct pvfs_file *f, struct odb_lock *lck)
966 struct pvfs_state *pvfs = ntvfs->private_data;
967 struct pvfs_file *f2;
968 struct pvfs_filename *name;
971 /* search for an existing open with the right parameters. Note
972 the magic ntcreatex options flag, which is set in the
973 generic mapping code. This might look ugly, but its
974 actually pretty much now w2k does it internally as well.
976 If you look at the BASE-DENYDOS test you will see that a
977 DENY_DOS is a very special case, and in the right
978 circumstances you actually get the _same_ handle back
979 twice, rather than a new handle.
981 for (f2=pvfs->files.list;f2;f2=f2->next) {
983 f2->ntvfs->session_info == req->session_info &&
984 f2->ntvfs->smbpid == req->smbpid &&
985 (f2->handle->create_options &
986 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
987 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
988 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
989 strcasecmp_m(f2->handle->name->original_name,
990 io->generic.in.fname)==0) {
996 return NT_STATUS_SHARING_VIOLATION;
999 /* quite an insane set of semantics ... */
1000 if (is_exe_filename(io->generic.in.fname) &&
1001 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1002 return NT_STATUS_SHARING_VIOLATION;
1006 setup a reference to the existing handle
1008 talloc_free(f->handle);
1009 f->handle = talloc_reference(f, f2->handle);
1013 name = f->handle->name;
1015 io->generic.out.oplock_level = OPLOCK_NONE;
1016 io->generic.out.file.ntvfs = f->ntvfs;
1017 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1018 io->generic.out.create_time = name->dos.create_time;
1019 io->generic.out.access_time = name->dos.access_time;
1020 io->generic.out.write_time = name->dos.write_time;
1021 io->generic.out.change_time = name->dos.change_time;
1022 io->generic.out.attrib = name->dos.attrib;
1023 io->generic.out.alloc_size = name->dos.alloc_size;
1024 io->generic.out.size = name->st.st_size;
1025 io->generic.out.file_type = FILE_TYPE_DISK;
1026 io->generic.out.ipc_state = 0;
1027 io->generic.out.is_directory = 0;
1029 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1030 NT_STATUS_NOT_OK_RETURN(status);
1032 return NT_STATUS_OK;
1038 setup for a open retry after a sharing violation
1040 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1041 struct ntvfs_request *req,
1043 struct pvfs_file *f,
1044 struct odb_lock *lck,
1045 NTSTATUS parent_status)
1047 struct pvfs_state *pvfs = ntvfs->private_data;
1049 struct timeval end_time;
1050 struct timeval *final_timeout = NULL;
1052 if (io->generic.in.create_options &
1053 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1054 /* see if we can satisfy the request using the special DENY_DOS
1056 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1057 if (NT_STATUS_IS_OK(status)) {
1062 /* the retry should allocate a new file handle */
1065 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1066 end_time = timeval_add(&req->statistics.request_time,
1067 0, pvfs->sharing_violation_delay);
1068 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1069 end_time = timeval_add(&req->statistics.request_time,
1070 pvfs->oplock_break_timeout, 0);
1071 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1073 * we got EAGAIN which means a unix application
1074 * has an oplock or share mode
1076 * we retry every 4/5 of the sharing violation delay
1077 * to see if the unix application
1078 * has released the oplock or share mode.
1080 final_timeout = talloc(req, struct timeval);
1081 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1082 *final_timeout = timeval_add(&req->statistics.request_time,
1083 pvfs->oplock_break_timeout,
1085 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1086 end_time = timeval_min(final_timeout, &end_time);
1088 return NT_STATUS_INTERNAL_ERROR;
1091 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1092 final_timeout, pvfs_retry_open_sharing);
1098 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1099 struct ntvfs_request *req, union smb_open *io)
1101 struct pvfs_state *pvfs = ntvfs->private_data;
1103 struct pvfs_filename *name;
1104 struct pvfs_file *f;
1105 struct ntvfs_handle *h;
1108 struct odb_lock *lck;
1109 uint32_t create_options;
1110 uint32_t share_access;
1111 uint32_t access_mask;
1113 bool stream_existed, stream_truncate=false;
1114 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1115 bool allow_level_II_oplock = false;
1117 /* use the generic mapping code to avoid implementing all the
1118 different open calls. */
1119 if (io->generic.level != RAW_OPEN_GENERIC &&
1120 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1121 return ntvfs_map_open(ntvfs, req, io);
1124 /* resolve the cifs name to a posix name */
1125 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1126 PVFS_RESOLVE_STREAMS, &name);
1127 if (!NT_STATUS_IS_OK(status)) {
1131 /* if the client specified that it must not be a directory then
1132 check that it isn't */
1133 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1134 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1135 return NT_STATUS_FILE_IS_A_DIRECTORY;
1138 /* if the client specified that it must be a directory then
1140 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1141 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1142 return NT_STATUS_NOT_A_DIRECTORY;
1145 /* directory opens are handled separately */
1146 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1147 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1148 return pvfs_open_directory(pvfs, req, name, io);
1151 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1152 open doesn't match */
1153 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1155 create_options = io->generic.in.create_options;
1156 share_access = io->generic.in.share_access;
1157 access_mask = io->generic.in.access_mask;
1159 /* certain create options are not allowed */
1160 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1161 !(access_mask & SEC_STD_DELETE)) {
1162 return NT_STATUS_INVALID_PARAMETER;
1167 switch (io->generic.in.open_disposition) {
1168 case NTCREATEX_DISP_SUPERSEDE:
1169 case NTCREATEX_DISP_OVERWRITE_IF:
1170 if (name->stream_name == NULL) {
1173 stream_truncate = true;
1177 case NTCREATEX_DISP_OPEN:
1178 if (!name->stream_exists) {
1179 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1184 case NTCREATEX_DISP_OVERWRITE:
1185 if (!name->stream_exists) {
1186 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1188 if (name->stream_name == NULL) {
1191 stream_truncate = true;
1195 case NTCREATEX_DISP_CREATE:
1196 if (name->stream_exists) {
1197 return NT_STATUS_OBJECT_NAME_COLLISION;
1202 case NTCREATEX_DISP_OPEN_IF:
1207 return NT_STATUS_INVALID_PARAMETER;
1210 /* handle creating a new file separately */
1211 if (!name->exists) {
1212 status = pvfs_create_file(pvfs, req, name, io);
1213 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1217 /* we've hit a race - the file was created during this call */
1218 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1222 /* try re-resolving the name */
1223 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1224 if (!NT_STATUS_IS_OK(status)) {
1227 /* fall through to a normal open */
1230 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1231 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1232 return NT_STATUS_CANNOT_DELETE;
1235 /* check the security descriptor */
1236 status = pvfs_access_check(pvfs, req, name, &access_mask);
1237 if (!NT_STATUS_IS_OK(status)) {
1241 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1242 NT_STATUS_NOT_OK_RETURN(status);
1244 f = talloc(h, struct pvfs_file);
1246 return NT_STATUS_NO_MEMORY;
1249 f->handle = talloc(f, struct pvfs_file_handle);
1250 if (f->handle == NULL) {
1251 return NT_STATUS_NO_MEMORY;
1256 f->pending_list = NULL;
1258 f->share_access = io->generic.in.share_access;
1259 f->access_mask = access_mask;
1260 f->impersonation = io->generic.in.impersonation;
1261 f->notify_buffer = NULL;
1264 f->handle->pvfs = pvfs;
1266 f->handle->name = talloc_steal(f->handle, name);
1267 f->handle->create_options = io->generic.in.create_options;
1268 f->handle->seek_offset = 0;
1269 f->handle->position = 0;
1270 f->handle->mode = 0;
1271 f->handle->oplock = NULL;
1272 f->handle->have_opendb_entry = false;
1273 f->handle->open_completed = false;
1275 /* form the lock context used for byte range locking and
1277 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1278 if (!NT_STATUS_IS_OK(status)) {
1282 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1283 if (!NT_STATUS_IS_OK(status)) {
1287 /* get a lock on this file before the actual open */
1288 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1290 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1292 /* we were supposed to do a blocking lock, so something
1294 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1297 DLIST_ADD(pvfs->files.list, f);
1299 /* setup a destructor to avoid file descriptor leaks on
1300 abnormal termination */
1301 talloc_set_destructor(f, pvfs_fnum_destructor);
1302 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1305 * Only SMB2 takes care of the delete_on_close,
1308 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1309 req->ctx->protocol == PROTOCOL_SMB2) {
1310 del_on_close = true;
1312 del_on_close = false;
1315 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1316 oplock_level = OPLOCK_NONE;
1317 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1318 oplock_level = OPLOCK_BATCH;
1319 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1320 oplock_level = OPLOCK_EXCLUSIVE;
1323 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1324 allow_level_II_oplock = true;
1327 /* see if we are allowed to open at the same time as existing opens */
1328 status = odb_can_open(lck, name->stream_id,
1329 share_access, access_mask, del_on_close,
1330 io->generic.in.open_disposition, false);
1333 * on a sharing violation we need to retry when the file is closed by
1334 * the other user, or after 1 second
1335 * on a non granted oplock we need to retry when the file is closed by
1336 * the other user, or after 30 seconds
1338 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1339 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1340 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1341 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1344 if (!NT_STATUS_IS_OK(status)) {
1349 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1355 /* do the actual open */
1356 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1358 status = pvfs_map_errno(f->pvfs, errno);
1361 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1363 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1364 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1365 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1374 /* now really mark the file as open */
1375 status = odb_open_file(lck, f->handle, name->full_name,
1376 &f->handle->fd, allow_level_II_oplock,
1377 oplock_level, &oplock_granted);
1379 if (!NT_STATUS_IS_OK(status)) {
1384 f->handle->have_opendb_entry = true;
1386 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1387 oplock_granted = OPLOCK_BATCH;
1388 } else if (oplock_granted != OPLOCK_NONE) {
1389 status = pvfs_setup_oplock(f, oplock_granted);
1390 if (!NT_STATUS_IS_OK(status)) {
1396 stream_existed = name->stream_exists;
1398 /* if this was a stream create then create the stream as well */
1399 if (!name->stream_exists) {
1400 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1401 if (!NT_STATUS_IS_OK(status)) {
1405 if (stream_truncate) {
1406 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1407 if (!NT_STATUS_IS_OK(status)) {
1414 /* re-resolve the open fd */
1415 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1416 if (!NT_STATUS_IS_OK(status)) {
1421 if (f->handle->name->stream_id == 0 &&
1422 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1423 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1424 /* for overwrite we need to replace file permissions */
1425 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1426 mode_t mode = pvfs_fileperms(pvfs, attrib);
1427 if (fchmod(fd, mode) == -1) {
1429 return pvfs_map_errno(pvfs, errno);
1431 name->dos.attrib = attrib;
1432 status = pvfs_dosattrib_save(pvfs, name, fd);
1433 if (!NT_STATUS_IS_OK(status)) {
1441 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1442 NT_STATUS_NOT_OK_RETURN(status);
1444 /* mark the open as having completed fully, so delete on close
1446 f->handle->open_completed = true;
1448 io->generic.out.oplock_level = oplock_granted;
1449 io->generic.out.file.ntvfs = h;
1450 io->generic.out.create_action = stream_existed?
1451 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1452 io->generic.out.create_time = name->dos.create_time;
1453 io->generic.out.access_time = name->dos.access_time;
1454 io->generic.out.write_time = name->dos.write_time;
1455 io->generic.out.change_time = name->dos.change_time;
1456 io->generic.out.attrib = name->dos.attrib;
1457 io->generic.out.alloc_size = name->dos.alloc_size;
1458 io->generic.out.size = name->st.st_size;
1459 io->generic.out.file_type = FILE_TYPE_DISK;
1460 io->generic.out.ipc_state = 0;
1461 io->generic.out.is_directory = 0;
1463 return NT_STATUS_OK;
1470 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1471 struct ntvfs_request *req, union smb_close *io)
1473 struct pvfs_state *pvfs = ntvfs->private_data;
1474 struct pvfs_file *f;
1475 struct utimbuf unix_times;
1477 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1478 return NT_STATUS_DOS(ERRSRV, ERRerror);
1481 if (io->generic.level != RAW_CLOSE_CLOSE) {
1482 return ntvfs_map_close(ntvfs, req, io);
1485 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1487 return NT_STATUS_INVALID_HANDLE;
1490 if (!null_time(io->close.in.write_time)) {
1491 unix_times.actime = 0;
1492 unix_times.modtime = io->close.in.write_time;
1493 utime(f->handle->name->full_name, &unix_times);
1498 return NT_STATUS_OK;
1503 logoff - close all file descriptors open by a vuid
1505 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1506 struct ntvfs_request *req)
1508 struct pvfs_state *pvfs = ntvfs->private_data;
1509 struct pvfs_file *f, *next;
1511 for (f=pvfs->files.list;f;f=next) {
1513 if (f->ntvfs->session_info == req->session_info) {
1518 return NT_STATUS_OK;
1523 exit - close files for the current pid
1525 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1526 struct ntvfs_request *req)
1528 struct pvfs_state *pvfs = ntvfs->private_data;
1529 struct pvfs_file *f, *next;
1531 for (f=pvfs->files.list;f;f=next) {
1533 if (f->ntvfs->session_info == req->session_info &&
1534 f->ntvfs->smbpid == req->smbpid) {
1539 return NT_STATUS_OK;
1544 change the delete on close flag on an already open file
1546 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1547 struct ntvfs_request *req,
1548 struct pvfs_file *f, bool del_on_close)
1550 struct odb_lock *lck;
1553 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1554 return NT_STATUS_CANNOT_DELETE;
1557 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1558 !pvfs_directory_empty(pvfs, f->handle->name)) {
1559 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1563 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1565 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1568 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1570 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1573 status = odb_set_delete_on_close(lck, del_on_close);
1582 determine if a file can be deleted, or if it is prevented by an
1585 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1586 struct ntvfs_request *req,
1587 struct pvfs_filename *name,
1588 struct odb_lock **lckp)
1592 struct odb_lock *lck;
1593 uint32_t share_access;
1594 uint32_t access_mask;
1595 bool delete_on_close;
1597 status = pvfs_locking_key(name, name, &key);
1598 if (!NT_STATUS_IS_OK(status)) {
1599 return NT_STATUS_NO_MEMORY;
1602 lck = odb_lock(req, pvfs->odb_context, &key);
1604 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1605 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1608 share_access = NTCREATEX_SHARE_ACCESS_READ |
1609 NTCREATEX_SHARE_ACCESS_WRITE |
1610 NTCREATEX_SHARE_ACCESS_DELETE;
1611 access_mask = SEC_STD_DELETE;
1612 delete_on_close = true;
1614 status = odb_can_open(lck, name->stream_id,
1615 share_access, access_mask, delete_on_close,
1616 NTCREATEX_DISP_OPEN, false);
1618 if (NT_STATUS_IS_OK(status)) {
1619 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1623 * if it's a sharing violation or we got no oplock
1624 * only keep the lock if the caller requested access
1627 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1628 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1634 } else if (!NT_STATUS_IS_OK(status)) {
1647 determine if a file can be renamed, or if it is prevented by an
1650 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1651 struct ntvfs_request *req,
1652 struct pvfs_filename *name,
1653 struct odb_lock **lckp)
1657 struct odb_lock *lck;
1658 uint32_t share_access;
1659 uint32_t access_mask;
1660 bool delete_on_close;
1662 status = pvfs_locking_key(name, name, &key);
1663 if (!NT_STATUS_IS_OK(status)) {
1664 return NT_STATUS_NO_MEMORY;
1667 lck = odb_lock(req, pvfs->odb_context, &key);
1669 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1670 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1673 share_access = NTCREATEX_SHARE_ACCESS_READ |
1674 NTCREATEX_SHARE_ACCESS_WRITE;
1675 access_mask = SEC_STD_DELETE;
1676 delete_on_close = false;
1678 status = odb_can_open(lck, name->stream_id,
1679 share_access, access_mask, delete_on_close,
1680 NTCREATEX_DISP_OPEN, false);
1683 * if it's a sharing violation or we got no oplock
1684 * only keep the lock if the caller requested access
1687 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1688 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1694 } else if (!NT_STATUS_IS_OK(status)) {
1707 determine if the file size of a file can be changed,
1708 or if it is prevented by an already open file
1710 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1711 struct ntvfs_request *req,
1712 struct pvfs_filename *name,
1713 struct odb_lock **lckp)
1717 struct odb_lock *lck;
1718 uint32_t share_access;
1719 uint32_t access_mask;
1721 bool delete_on_close;
1723 status = pvfs_locking_key(name, name, &key);
1724 if (!NT_STATUS_IS_OK(status)) {
1725 return NT_STATUS_NO_MEMORY;
1728 lck = odb_lock(req, pvfs->odb_context, &key);
1730 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1731 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1734 share_access = NTCREATEX_SHARE_ACCESS_READ |
1735 NTCREATEX_SHARE_ACCESS_WRITE |
1736 NTCREATEX_SHARE_ACCESS_DELETE;
1738 * I would have thought that we would need to pass
1739 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1741 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1742 * to set the filesize.
1746 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1747 delete_on_close = false;
1748 break_to_none = true;
1750 status = odb_can_open(lck, name->stream_id,
1751 share_access, access_mask, delete_on_close,
1752 NTCREATEX_DISP_OPEN, break_to_none);
1755 * if it's a sharing violation or we got no oplock
1756 * only keep the lock if the caller requested access
1759 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1760 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1766 } else if (!NT_STATUS_IS_OK(status)) {
1779 determine if file meta data can be accessed, or if it is prevented by an
1782 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1783 struct ntvfs_request *req,
1784 struct pvfs_filename *name)
1788 struct odb_lock *lck;
1789 uint32_t share_access;
1790 uint32_t access_mask;
1791 bool delete_on_close;
1793 status = pvfs_locking_key(name, name, &key);
1794 if (!NT_STATUS_IS_OK(status)) {
1795 return NT_STATUS_NO_MEMORY;
1798 lck = odb_lock(req, pvfs->odb_context, &key);
1800 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1801 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1804 share_access = NTCREATEX_SHARE_ACCESS_READ |
1805 NTCREATEX_SHARE_ACCESS_WRITE;
1806 access_mask = SEC_FILE_READ_ATTRIBUTE;
1807 delete_on_close = false;
1809 status = odb_can_open(lck, name->stream_id,
1810 share_access, access_mask, delete_on_close,
1811 NTCREATEX_DISP_OPEN, false);
1813 if (!NT_STATUS_IS_OK(status)) {
1822 determine if delete on close is set on
1824 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1829 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1831 if (!NT_STATUS_IS_OK(status)) {
1832 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1836 return del_on_close;