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 /* found with gentest */
207 if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
208 (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
209 (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
210 return NT_STATUS_INVALID_PARAMETER;
213 switch (io->generic.in.open_disposition) {
214 case NTCREATEX_DISP_OPEN_IF:
217 case NTCREATEX_DISP_OPEN:
219 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
223 case NTCREATEX_DISP_CREATE:
225 return NT_STATUS_OBJECT_NAME_COLLISION;
229 case NTCREATEX_DISP_OVERWRITE_IF:
230 case NTCREATEX_DISP_OVERWRITE:
231 case NTCREATEX_DISP_SUPERSEDE:
233 return NT_STATUS_INVALID_PARAMETER;
236 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
237 NT_STATUS_NOT_OK_RETURN(status);
239 f = talloc(h, struct pvfs_file);
241 return NT_STATUS_NO_MEMORY;
244 f->handle = talloc(f, struct pvfs_file_handle);
245 if (f->handle == NULL) {
246 return NT_STATUS_NO_MEMORY;
250 /* check the security descriptor */
251 status = pvfs_access_check(pvfs, req, name, &access_mask);
253 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
255 if (!NT_STATUS_IS_OK(status)) {
261 f->pending_list = NULL;
263 f->share_access = io->generic.in.share_access;
264 f->impersonation = io->generic.in.impersonation;
265 f->access_mask = access_mask;
266 f->brl_handle = NULL;
267 f->notify_buffer = NULL;
270 f->handle->pvfs = pvfs;
271 f->handle->name = talloc_steal(f->handle, name);
273 f->handle->odb_locking_key = data_blob(NULL, 0);
274 f->handle->create_options = io->generic.in.create_options;
275 f->handle->seek_offset = 0;
276 f->handle->position = 0;
278 f->handle->oplock = NULL;
279 f->handle->open_completed = false;
281 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
282 pvfs_directory_empty(pvfs, f->handle->name)) {
285 del_on_close = false;
289 /* form the lock context used for opendb locking */
290 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
291 if (!NT_STATUS_IS_OK(status)) {
295 /* get a lock on this file before the actual open */
296 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
298 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
300 /* we were supposed to do a blocking lock, so something
302 return NT_STATUS_INTERNAL_DB_CORRUPTION;
305 /* see if we are allowed to open at the same time as existing opens */
306 status = odb_can_open(lck, name->stream_id,
307 share_access, access_mask, del_on_close,
308 io->generic.in.open_disposition, false);
309 if (!NT_STATUS_IS_OK(status)) {
314 /* now really mark the file as open */
315 status = odb_open_file(lck, f->handle, name->full_name,
316 NULL, false, OPLOCK_NONE, NULL);
318 if (!NT_STATUS_IS_OK(status)) {
323 f->handle->have_opendb_entry = true;
326 DLIST_ADD(pvfs->files.list, f);
328 /* setup destructors to avoid leaks on abnormal termination */
329 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
330 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
333 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
334 mode_t mode = pvfs_fileperms(pvfs, attrib);
336 if (mkdir(name->full_name, mode) == -1) {
337 return pvfs_map_errno(pvfs,errno);
340 pvfs_xattr_unlink_hook(pvfs, name->full_name);
342 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
343 if (!NT_STATUS_IS_OK(status)) {
347 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
348 if (!NT_STATUS_IS_OK(status)) {
352 /* form the lock context used for opendb locking */
353 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
354 if (!NT_STATUS_IS_OK(status)) {
358 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
360 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
362 /* we were supposed to do a blocking lock, so something
364 return NT_STATUS_INTERNAL_DB_CORRUPTION;
367 status = odb_can_open(lck, name->stream_id,
368 share_access, access_mask, del_on_close,
369 io->generic.in.open_disposition, false);
371 if (!NT_STATUS_IS_OK(status)) {
375 status = odb_open_file(lck, f->handle, name->full_name,
376 NULL, false, OPLOCK_NONE, NULL);
378 if (!NT_STATUS_IS_OK(status)) {
382 f->handle->have_opendb_entry = true;
384 create_action = NTCREATEX_ACTION_CREATED;
386 notify_trigger(pvfs->notify_context,
388 FILE_NOTIFY_CHANGE_DIR_NAME,
391 create_action = NTCREATEX_ACTION_EXISTED;
395 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
398 /* the open succeeded, keep this handle permanently */
399 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
400 if (!NT_STATUS_IS_OK(status)) {
404 f->handle->open_completed = true;
406 io->generic.out.oplock_level = OPLOCK_NONE;
407 io->generic.out.file.ntvfs = h;
408 io->generic.out.create_action = create_action;
409 io->generic.out.create_time = name->dos.create_time;
410 io->generic.out.access_time = name->dos.access_time;
411 io->generic.out.write_time = name->dos.write_time;
412 io->generic.out.change_time = name->dos.change_time;
413 io->generic.out.attrib = name->dos.attrib;
414 io->generic.out.alloc_size = name->dos.alloc_size;
415 io->generic.out.size = name->st.st_size;
416 io->generic.out.file_type = FILE_TYPE_DISK;
417 io->generic.out.ipc_state = 0;
418 io->generic.out.is_directory = 1;
423 rmdir(name->full_name);
428 destroy a struct pvfs_file_handle
430 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
432 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
433 h->name->stream_name) {
435 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
436 if (!NT_STATUS_IS_OK(status)) {
437 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
438 h->name->stream_name, h->name->full_name));
443 if (close(h->fd) != 0) {
444 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
445 h->fd, h->name->full_name, strerror(errno)));
450 if (h->have_opendb_entry) {
451 struct odb_lock *lck;
453 const char *delete_path = NULL;
455 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
457 DEBUG(0,("Unable to lock opendb for close\n"));
461 status = odb_close_file(lck, h, &delete_path);
462 if (!NT_STATUS_IS_OK(status)) {
463 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
464 h->name->full_name, nt_errstr(status)));
467 if (h->name->stream_name == NULL &&
468 h->open_completed && delete_path) {
469 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
470 if (!NT_STATUS_IS_OK(status)) {
471 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
472 delete_path, nt_errstr(status)));
474 if (unlink(delete_path) != 0) {
475 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
476 delete_path, strerror(errno)));
478 notify_trigger(h->pvfs->notify_context,
479 NOTIFY_ACTION_REMOVED,
480 FILE_NOTIFY_CHANGE_FILE_NAME,
493 destroy a struct pvfs_file
495 static int pvfs_fnum_destructor(struct pvfs_file *f)
497 DLIST_REMOVE(f->pvfs->files.list, f);
498 pvfs_lock_close(f->pvfs, f);
499 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
506 form the lock context used for byte range locking. This is separate
507 from the locking key used for opendb locking as it needs to take
508 account of file streams (each stream is a separate byte range
511 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
512 struct pvfs_filename *name,
513 struct ntvfs_handle *ntvfs,
514 struct brl_handle **_h)
516 DATA_BLOB odb_key, key;
518 struct brl_handle *h;
520 status = pvfs_locking_key(name, mem_ctx, &odb_key);
521 NT_STATUS_NOT_OK_RETURN(status);
523 if (name->stream_name == NULL) {
526 key = data_blob_talloc(mem_ctx, NULL,
527 odb_key.length + strlen(name->stream_name) + 1);
528 NT_STATUS_HAVE_NO_MEMORY(key.data);
529 memcpy(key.data, odb_key.data, odb_key.length);
530 memcpy(key.data + odb_key.length,
531 name->stream_name, strlen(name->stream_name) + 1);
532 data_blob_free(&odb_key);
535 h = brl_create_handle(mem_ctx, ntvfs, &key);
536 NT_STATUS_HAVE_NO_MEMORY(h);
545 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
546 struct ntvfs_request *req,
547 struct pvfs_filename *name,
552 struct ntvfs_handle *h;
554 struct odb_lock *lck;
555 uint32_t create_options = io->generic.in.create_options;
556 uint32_t share_access = io->generic.in.share_access;
557 uint32_t access_mask = io->generic.in.access_mask;
561 struct pvfs_filename *parent;
562 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
563 bool allow_level_II_oplock = false;
565 if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
566 return NT_STATUS_INVALID_PARAMETER;
569 if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
570 return NT_STATUS_ACCESS_DENIED;
573 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
574 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
575 return NT_STATUS_CANNOT_DELETE;
578 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
579 NT_STATUS_NOT_OK_RETURN(status);
581 /* check that the parent isn't opened with delete on close set */
582 status = pvfs_resolve_parent(pvfs, req, name, &parent);
583 if (NT_STATUS_IS_OK(status)) {
584 DATA_BLOB locking_key;
585 status = pvfs_locking_key(parent, req, &locking_key);
586 NT_STATUS_NOT_OK_RETURN(status);
587 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key,
589 NT_STATUS_NOT_OK_RETURN(status);
591 return NT_STATUS_DELETE_PENDING;
595 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
601 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
602 NT_STATUS_NOT_OK_RETURN(status);
604 f = talloc(h, struct pvfs_file);
605 NT_STATUS_HAVE_NO_MEMORY(f);
607 f->handle = talloc(f, struct pvfs_file_handle);
608 NT_STATUS_HAVE_NO_MEMORY(f->handle);
610 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
611 mode = pvfs_fileperms(pvfs, attrib);
613 /* create the file */
614 fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
616 return pvfs_map_errno(pvfs, errno);
619 pvfs_xattr_unlink_hook(pvfs, name->full_name);
621 /* if this was a stream create then create the stream as well */
622 if (name->stream_name) {
623 status = pvfs_stream_create(pvfs, name, fd);
624 if (!NT_STATUS_IS_OK(status)) {
630 /* re-resolve the open fd */
631 status = pvfs_resolve_name_fd(pvfs, fd, name);
632 if (!NT_STATUS_IS_OK(status)) {
637 name->dos.attrib = attrib;
638 status = pvfs_dosattrib_save(pvfs, name, fd);
639 if (!NT_STATUS_IS_OK(status)) {
644 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
645 if (!NT_STATUS_IS_OK(status)) {
649 /* form the lock context used for byte range locking and
651 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
652 if (!NT_STATUS_IS_OK(status)) {
656 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
657 if (!NT_STATUS_IS_OK(status)) {
661 /* grab a lock on the open file record */
662 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
664 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
666 /* we were supposed to do a blocking lock, so something
668 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
672 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
675 del_on_close = false;
678 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
679 oplock_level = OPLOCK_NONE;
680 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
681 oplock_level = OPLOCK_BATCH;
682 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
683 oplock_level = OPLOCK_EXCLUSIVE;
686 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
687 allow_level_II_oplock = true;
690 status = odb_can_open(lck, name->stream_id,
691 share_access, access_mask, del_on_close,
692 io->generic.in.open_disposition, false);
693 if (!NT_STATUS_IS_OK(status)) {
695 /* bad news, we must have hit a race - we don't delete the file
696 here as the most likely scenario is that someone else created
697 the file at the same time */
704 f->pending_list = NULL;
706 f->share_access = io->generic.in.share_access;
707 f->access_mask = access_mask;
708 f->impersonation = io->generic.in.impersonation;
709 f->notify_buffer = NULL;
712 f->handle->pvfs = pvfs;
713 f->handle->name = talloc_steal(f->handle, name);
715 f->handle->create_options = io->generic.in.create_options;
716 f->handle->seek_offset = 0;
717 f->handle->position = 0;
719 f->handle->oplock = NULL;
720 f->handle->have_opendb_entry = true;
721 f->handle->open_completed = false;
723 status = odb_open_file(lck, f->handle, name->full_name,
724 &f->handle->fd, allow_level_II_oplock,
725 oplock_level, &oplock_granted);
727 if (!NT_STATUS_IS_OK(status)) {
728 /* bad news, we must have hit a race - we don't delete the file
729 here as the most likely scenario is that someone else created
730 the file at the same time */
735 DLIST_ADD(pvfs->files.list, f);
737 /* setup a destructor to avoid file descriptor leaks on
738 abnormal termination */
739 talloc_set_destructor(f, pvfs_fnum_destructor);
740 talloc_set_destructor(f->handle, pvfs_handle_destructor);
742 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
743 oplock_granted = OPLOCK_BATCH;
744 } else if (oplock_granted != OPLOCK_NONE) {
745 status = pvfs_setup_oplock(f, oplock_granted);
746 if (!NT_STATUS_IS_OK(status)) {
751 io->generic.out.oplock_level = oplock_granted;
752 io->generic.out.file.ntvfs = f->ntvfs;
753 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
754 io->generic.out.create_time = name->dos.create_time;
755 io->generic.out.access_time = name->dos.access_time;
756 io->generic.out.write_time = name->dos.write_time;
757 io->generic.out.change_time = name->dos.change_time;
758 io->generic.out.attrib = name->dos.attrib;
759 io->generic.out.alloc_size = name->dos.alloc_size;
760 io->generic.out.size = name->st.st_size;
761 io->generic.out.file_type = FILE_TYPE_DISK;
762 io->generic.out.ipc_state = 0;
763 io->generic.out.is_directory = 0;
765 /* success - keep the file handle */
766 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
767 if (!NT_STATUS_IS_OK(status)) {
771 f->handle->open_completed = true;
773 notify_trigger(pvfs->notify_context,
775 FILE_NOTIFY_CHANGE_FILE_NAME,
782 unlink(name->full_name);
787 state of a pending retry
789 struct pvfs_odb_retry {
790 struct ntvfs_module_context *ntvfs;
791 struct ntvfs_request *req;
792 DATA_BLOB odb_locking_key;
795 void (*callback)(struct pvfs_odb_retry *r,
796 struct ntvfs_module_context *ntvfs,
797 struct ntvfs_request *req,
800 enum pvfs_wait_notice reason);
803 /* destroy a pending request */
804 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
806 struct pvfs_state *pvfs = r->ntvfs->private_data;
807 if (r->odb_locking_key.data) {
808 struct odb_lock *lck;
809 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
811 odb_remove_pending(lck, r);
818 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
820 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
822 if (reason == PVFS_WAIT_EVENT) {
824 * The pending odb entry is already removed.
825 * We use a null locking key to indicate this
828 data_blob_free(&r->odb_locking_key);
831 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
835 setup for a retry of a request that was rejected
838 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
839 struct ntvfs_request *req,
840 struct odb_lock *lck,
841 struct timeval end_time,
844 void (*callback)(struct pvfs_odb_retry *r,
845 struct ntvfs_module_context *ntvfs,
846 struct ntvfs_request *req,
849 enum pvfs_wait_notice reason))
851 struct pvfs_state *pvfs = ntvfs->private_data;
852 struct pvfs_odb_retry *r;
853 struct pvfs_wait *wait_handle;
856 r = talloc(req, struct pvfs_odb_retry);
857 NT_STATUS_HAVE_NO_MEMORY(r);
862 r->private_data = private_data;
863 r->callback = callback;
864 r->odb_locking_key = odb_get_key(r, lck);
865 if (r->odb_locking_key.data == NULL) {
866 return NT_STATUS_NO_MEMORY;
869 /* setup a pending lock */
870 status = odb_open_file_pending(lck, r);
871 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
873 * maybe only a unix application
876 data_blob_free(&r->odb_locking_key);
877 } else if (!NT_STATUS_IS_OK(status)) {
883 talloc_set_destructor(r, pvfs_odb_retry_destructor);
885 wait_handle = pvfs_wait_message(pvfs, req,
886 MSG_PVFS_RETRY_OPEN, end_time,
887 pvfs_odb_retry_callback, r);
888 if (wait_handle == NULL) {
889 return NT_STATUS_NO_MEMORY;
892 talloc_steal(r, wait_handle);
898 retry an open after a sharing violation
900 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
901 struct ntvfs_module_context *ntvfs,
902 struct ntvfs_request *req,
905 enum pvfs_wait_notice reason)
907 union smb_open *io = talloc_get_type(_io, union smb_open);
908 struct timeval *final_timeout = NULL;
912 final_timeout = talloc_get_type(private_data,
916 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
917 just a bug in their server, but we better do the same */
918 if (reason == PVFS_WAIT_CANCEL) {
922 if (reason == PVFS_WAIT_TIMEOUT) {
924 !timeval_expired(final_timeout)) {
926 * we need to retry periodictly
927 * after an EAGAIN as there's
928 * no way the kernel tell us
929 * an oplock is released.
933 /* if it timed out, then give the failure
936 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
937 req->async_states->send_fn(req);
944 /* try the open again, which could trigger another retry setup
945 if it wants to, so we have to unmark the async flag so we
946 will know if it does a second async reply */
947 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
949 status = pvfs_open(ntvfs, req, io);
950 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
951 /* the 2nd try also replied async, so we don't send
956 /* re-mark it async, just in case someone up the chain does
958 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
960 /* send the reply up the chain */
961 req->async_states->status = status;
962 req->async_states->send_fn(req);
967 special handling for openx DENY_DOS semantics
969 This function attempts a reference open using an existing handle. If its allowed,
970 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
971 open processing continues.
973 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
974 struct ntvfs_request *req, union smb_open *io,
975 struct pvfs_file *f, struct odb_lock *lck)
977 struct pvfs_state *pvfs = ntvfs->private_data;
978 struct pvfs_file *f2;
979 struct pvfs_filename *name;
982 /* search for an existing open with the right parameters. Note
983 the magic ntcreatex options flag, which is set in the
984 generic mapping code. This might look ugly, but its
985 actually pretty much now w2k does it internally as well.
987 If you look at the BASE-DENYDOS test you will see that a
988 DENY_DOS is a very special case, and in the right
989 circumstances you actually get the _same_ handle back
990 twice, rather than a new handle.
992 for (f2=pvfs->files.list;f2;f2=f2->next) {
994 f2->ntvfs->session_info == req->session_info &&
995 f2->ntvfs->smbpid == req->smbpid &&
996 (f2->handle->create_options &
997 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
998 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
999 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1000 strcasecmp_m(f2->handle->name->original_name,
1001 io->generic.in.fname)==0) {
1007 return NT_STATUS_SHARING_VIOLATION;
1010 /* quite an insane set of semantics ... */
1011 if (is_exe_filename(io->generic.in.fname) &&
1012 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1013 return NT_STATUS_SHARING_VIOLATION;
1017 setup a reference to the existing handle
1019 talloc_free(f->handle);
1020 f->handle = talloc_reference(f, f2->handle);
1024 name = f->handle->name;
1026 io->generic.out.oplock_level = OPLOCK_NONE;
1027 io->generic.out.file.ntvfs = f->ntvfs;
1028 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1029 io->generic.out.create_time = name->dos.create_time;
1030 io->generic.out.access_time = name->dos.access_time;
1031 io->generic.out.write_time = name->dos.write_time;
1032 io->generic.out.change_time = name->dos.change_time;
1033 io->generic.out.attrib = name->dos.attrib;
1034 io->generic.out.alloc_size = name->dos.alloc_size;
1035 io->generic.out.size = name->st.st_size;
1036 io->generic.out.file_type = FILE_TYPE_DISK;
1037 io->generic.out.ipc_state = 0;
1038 io->generic.out.is_directory = 0;
1040 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1041 NT_STATUS_NOT_OK_RETURN(status);
1043 return NT_STATUS_OK;
1049 setup for a open retry after a sharing violation
1051 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1052 struct ntvfs_request *req,
1054 struct pvfs_file *f,
1055 struct odb_lock *lck,
1056 NTSTATUS parent_status)
1058 struct pvfs_state *pvfs = ntvfs->private_data;
1060 struct timeval end_time;
1061 struct timeval *final_timeout = NULL;
1063 if (io->generic.in.create_options &
1064 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1065 /* see if we can satisfy the request using the special DENY_DOS
1067 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1068 if (NT_STATUS_IS_OK(status)) {
1073 /* the retry should allocate a new file handle */
1076 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1077 end_time = timeval_add(&req->statistics.request_time,
1078 0, pvfs->sharing_violation_delay);
1079 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1080 end_time = timeval_add(&req->statistics.request_time,
1081 pvfs->oplock_break_timeout, 0);
1082 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1084 * we got EAGAIN which means a unix application
1085 * has an oplock or share mode
1087 * we retry every 4/5 of the sharing violation delay
1088 * to see if the unix application
1089 * has released the oplock or share mode.
1091 final_timeout = talloc(req, struct timeval);
1092 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1093 *final_timeout = timeval_add(&req->statistics.request_time,
1094 pvfs->oplock_break_timeout,
1096 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1097 end_time = timeval_min(final_timeout, &end_time);
1099 return NT_STATUS_INTERNAL_ERROR;
1102 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1103 final_timeout, pvfs_retry_open_sharing);
1109 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1110 struct ntvfs_request *req, union smb_open *io)
1112 struct pvfs_state *pvfs = ntvfs->private_data;
1114 struct pvfs_filename *name;
1115 struct pvfs_file *f;
1116 struct ntvfs_handle *h;
1119 struct odb_lock *lck;
1120 uint32_t create_options;
1121 uint32_t share_access;
1122 uint32_t access_mask;
1124 bool stream_existed, stream_truncate=false;
1125 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1126 bool allow_level_II_oplock = false;
1128 /* use the generic mapping code to avoid implementing all the
1129 different open calls. */
1130 if (io->generic.level != RAW_OPEN_GENERIC &&
1131 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1132 return ntvfs_map_open(ntvfs, req, io);
1135 create_options = io->generic.in.create_options;
1136 share_access = io->generic.in.share_access;
1137 access_mask = io->generic.in.access_mask;
1139 if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1140 return NT_STATUS_INVALID_PARAMETER;
1143 /* some create options are not supported */
1144 if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1145 return NT_STATUS_NOT_SUPPORTED;
1148 /* other create options are not allowed */
1149 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1150 !(access_mask & SEC_STD_DELETE)) {
1151 return NT_STATUS_INVALID_PARAMETER;
1154 if (access_mask & SEC_MASK_INVALID) {
1155 return NT_STATUS_ACCESS_DENIED;
1158 /* what does this bit really mean?? */
1159 if (req->ctx->protocol == PROTOCOL_SMB2 &&
1160 (access_mask & SEC_STD_SYNCHRONIZE) &&
1161 !(access_mask & SEC_STD_READ_CONTROL)) {
1162 return NT_STATUS_ACCESS_DENIED;
1165 if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1166 FILE_ATTRIBUTE_VOLUME|
1167 (~FILE_ATTRIBUTE_ALL_MASK))) {
1168 return NT_STATUS_INVALID_PARAMETER;
1171 /* resolve the cifs name to a posix name */
1172 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1173 PVFS_RESOLVE_STREAMS, &name);
1174 if (!NT_STATUS_IS_OK(status)) {
1178 /* if the client specified that it must not be a directory then
1179 check that it isn't */
1180 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1181 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1182 return NT_STATUS_FILE_IS_A_DIRECTORY;
1185 /* if the client specified that it must be a directory then
1187 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1188 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1189 return NT_STATUS_NOT_A_DIRECTORY;
1192 /* directory opens are handled separately */
1193 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1194 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1195 return pvfs_open_directory(pvfs, req, name, io);
1198 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1199 open doesn't match */
1200 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1204 switch (io->generic.in.open_disposition) {
1205 case NTCREATEX_DISP_SUPERSEDE:
1206 case NTCREATEX_DISP_OVERWRITE_IF:
1207 if (name->stream_name == NULL) {
1210 stream_truncate = true;
1214 case NTCREATEX_DISP_OPEN:
1215 if (!name->stream_exists) {
1216 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1221 case NTCREATEX_DISP_OVERWRITE:
1222 if (!name->stream_exists) {
1223 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1225 if (name->stream_name == NULL) {
1228 stream_truncate = true;
1232 case NTCREATEX_DISP_CREATE:
1233 if (name->stream_exists) {
1234 return NT_STATUS_OBJECT_NAME_COLLISION;
1239 case NTCREATEX_DISP_OPEN_IF:
1244 return NT_STATUS_INVALID_PARAMETER;
1247 /* handle creating a new file separately */
1248 if (!name->exists) {
1249 status = pvfs_create_file(pvfs, req, name, io);
1250 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1254 /* we've hit a race - the file was created during this call */
1255 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1259 /* try re-resolving the name */
1260 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1261 if (!NT_STATUS_IS_OK(status)) {
1264 /* fall through to a normal open */
1267 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1268 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1269 return NT_STATUS_CANNOT_DELETE;
1272 /* check the security descriptor */
1273 status = pvfs_access_check(pvfs, req, name, &access_mask);
1274 if (!NT_STATUS_IS_OK(status)) {
1278 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1279 NT_STATUS_NOT_OK_RETURN(status);
1281 f = talloc(h, struct pvfs_file);
1283 return NT_STATUS_NO_MEMORY;
1286 f->handle = talloc(f, struct pvfs_file_handle);
1287 if (f->handle == NULL) {
1288 return NT_STATUS_NO_MEMORY;
1293 f->pending_list = NULL;
1295 f->share_access = io->generic.in.share_access;
1296 f->access_mask = access_mask;
1297 f->impersonation = io->generic.in.impersonation;
1298 f->notify_buffer = NULL;
1301 f->handle->pvfs = pvfs;
1303 f->handle->name = talloc_steal(f->handle, name);
1304 f->handle->create_options = io->generic.in.create_options;
1305 f->handle->seek_offset = 0;
1306 f->handle->position = 0;
1307 f->handle->mode = 0;
1308 f->handle->oplock = NULL;
1309 f->handle->have_opendb_entry = false;
1310 f->handle->open_completed = false;
1312 /* form the lock context used for byte range locking and
1314 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1315 if (!NT_STATUS_IS_OK(status)) {
1319 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1320 if (!NT_STATUS_IS_OK(status)) {
1324 /* get a lock on this file before the actual open */
1325 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1327 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1329 /* we were supposed to do a blocking lock, so something
1331 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1334 DLIST_ADD(pvfs->files.list, f);
1336 /* setup a destructor to avoid file descriptor leaks on
1337 abnormal termination */
1338 talloc_set_destructor(f, pvfs_fnum_destructor);
1339 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1342 * Only SMB2 takes care of the delete_on_close,
1345 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1346 req->ctx->protocol == PROTOCOL_SMB2) {
1347 del_on_close = true;
1349 del_on_close = false;
1352 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1353 oplock_level = OPLOCK_NONE;
1354 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1355 oplock_level = OPLOCK_BATCH;
1356 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1357 oplock_level = OPLOCK_EXCLUSIVE;
1360 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1361 allow_level_II_oplock = true;
1364 /* see if we are allowed to open at the same time as existing opens */
1365 status = odb_can_open(lck, name->stream_id,
1366 share_access, access_mask, del_on_close,
1367 io->generic.in.open_disposition, false);
1370 * on a sharing violation we need to retry when the file is closed by
1371 * the other user, or after 1 second
1372 * on a non granted oplock we need to retry when the file is closed by
1373 * the other user, or after 30 seconds
1375 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1376 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1377 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1378 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1381 if (!NT_STATUS_IS_OK(status)) {
1386 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1392 /* do the actual open */
1393 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1395 status = pvfs_map_errno(f->pvfs, errno);
1398 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1400 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1401 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1402 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1411 /* now really mark the file as open */
1412 status = odb_open_file(lck, f->handle, name->full_name,
1413 &f->handle->fd, allow_level_II_oplock,
1414 oplock_level, &oplock_granted);
1416 if (!NT_STATUS_IS_OK(status)) {
1421 f->handle->have_opendb_entry = true;
1423 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1424 oplock_granted = OPLOCK_BATCH;
1425 } else if (oplock_granted != OPLOCK_NONE) {
1426 status = pvfs_setup_oplock(f, oplock_granted);
1427 if (!NT_STATUS_IS_OK(status)) {
1433 stream_existed = name->stream_exists;
1435 /* if this was a stream create then create the stream as well */
1436 if (!name->stream_exists) {
1437 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1438 if (!NT_STATUS_IS_OK(status)) {
1442 if (stream_truncate) {
1443 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1444 if (!NT_STATUS_IS_OK(status)) {
1451 /* re-resolve the open fd */
1452 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1453 if (!NT_STATUS_IS_OK(status)) {
1458 if (f->handle->name->stream_id == 0 &&
1459 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1460 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1461 /* for overwrite we need to replace file permissions */
1462 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1463 mode_t mode = pvfs_fileperms(pvfs, attrib);
1464 if (fchmod(fd, mode) == -1) {
1466 return pvfs_map_errno(pvfs, errno);
1468 name->dos.attrib = attrib;
1469 status = pvfs_dosattrib_save(pvfs, name, fd);
1470 if (!NT_STATUS_IS_OK(status)) {
1478 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1479 NT_STATUS_NOT_OK_RETURN(status);
1481 /* mark the open as having completed fully, so delete on close
1483 f->handle->open_completed = true;
1485 io->generic.out.oplock_level = oplock_granted;
1486 io->generic.out.file.ntvfs = h;
1487 io->generic.out.create_action = stream_existed?
1488 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1489 io->generic.out.create_time = name->dos.create_time;
1490 io->generic.out.access_time = name->dos.access_time;
1491 io->generic.out.write_time = name->dos.write_time;
1492 io->generic.out.change_time = name->dos.change_time;
1493 io->generic.out.attrib = name->dos.attrib;
1494 io->generic.out.alloc_size = name->dos.alloc_size;
1495 io->generic.out.size = name->st.st_size;
1496 io->generic.out.file_type = FILE_TYPE_DISK;
1497 io->generic.out.ipc_state = 0;
1498 io->generic.out.is_directory = 0;
1500 return NT_STATUS_OK;
1507 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1508 struct ntvfs_request *req, union smb_close *io)
1510 struct pvfs_state *pvfs = ntvfs->private_data;
1511 struct pvfs_file *f;
1512 struct utimbuf unix_times;
1514 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1515 return NT_STATUS_DOS(ERRSRV, ERRerror);
1518 if (io->generic.level != RAW_CLOSE_CLOSE) {
1519 return ntvfs_map_close(ntvfs, req, io);
1522 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1524 return NT_STATUS_INVALID_HANDLE;
1527 if (!null_time(io->close.in.write_time)) {
1528 unix_times.actime = 0;
1529 unix_times.modtime = io->close.in.write_time;
1530 utime(f->handle->name->full_name, &unix_times);
1535 return NT_STATUS_OK;
1540 logoff - close all file descriptors open by a vuid
1542 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1543 struct ntvfs_request *req)
1545 struct pvfs_state *pvfs = ntvfs->private_data;
1546 struct pvfs_file *f, *next;
1548 for (f=pvfs->files.list;f;f=next) {
1550 if (f->ntvfs->session_info == req->session_info) {
1555 return NT_STATUS_OK;
1560 exit - close files for the current pid
1562 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1563 struct ntvfs_request *req)
1565 struct pvfs_state *pvfs = ntvfs->private_data;
1566 struct pvfs_file *f, *next;
1568 for (f=pvfs->files.list;f;f=next) {
1570 if (f->ntvfs->session_info == req->session_info &&
1571 f->ntvfs->smbpid == req->smbpid) {
1576 return NT_STATUS_OK;
1581 change the delete on close flag on an already open file
1583 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1584 struct ntvfs_request *req,
1585 struct pvfs_file *f, bool del_on_close)
1587 struct odb_lock *lck;
1590 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1591 return NT_STATUS_CANNOT_DELETE;
1594 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1595 !pvfs_directory_empty(pvfs, f->handle->name)) {
1596 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1600 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1602 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1605 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1607 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1610 status = odb_set_delete_on_close(lck, del_on_close);
1619 determine if a file can be deleted, or if it is prevented by an
1622 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1623 struct ntvfs_request *req,
1624 struct pvfs_filename *name,
1625 struct odb_lock **lckp)
1629 struct odb_lock *lck;
1630 uint32_t share_access;
1631 uint32_t access_mask;
1632 bool delete_on_close;
1634 status = pvfs_locking_key(name, name, &key);
1635 if (!NT_STATUS_IS_OK(status)) {
1636 return NT_STATUS_NO_MEMORY;
1639 lck = odb_lock(req, pvfs->odb_context, &key);
1641 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1642 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1645 share_access = NTCREATEX_SHARE_ACCESS_READ |
1646 NTCREATEX_SHARE_ACCESS_WRITE |
1647 NTCREATEX_SHARE_ACCESS_DELETE;
1648 access_mask = SEC_STD_DELETE;
1649 delete_on_close = true;
1651 status = odb_can_open(lck, name->stream_id,
1652 share_access, access_mask, delete_on_close,
1653 NTCREATEX_DISP_OPEN, false);
1655 if (NT_STATUS_IS_OK(status)) {
1656 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1660 * if it's a sharing violation or we got no oplock
1661 * only keep the lock if the caller requested access
1664 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1665 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1671 } else if (!NT_STATUS_IS_OK(status)) {
1684 determine if a file can be renamed, or if it is prevented by an
1687 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1688 struct ntvfs_request *req,
1689 struct pvfs_filename *name,
1690 struct odb_lock **lckp)
1694 struct odb_lock *lck;
1695 uint32_t share_access;
1696 uint32_t access_mask;
1697 bool delete_on_close;
1699 status = pvfs_locking_key(name, name, &key);
1700 if (!NT_STATUS_IS_OK(status)) {
1701 return NT_STATUS_NO_MEMORY;
1704 lck = odb_lock(req, pvfs->odb_context, &key);
1706 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1707 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1710 share_access = NTCREATEX_SHARE_ACCESS_READ |
1711 NTCREATEX_SHARE_ACCESS_WRITE;
1712 access_mask = SEC_STD_DELETE;
1713 delete_on_close = false;
1715 status = odb_can_open(lck, name->stream_id,
1716 share_access, access_mask, delete_on_close,
1717 NTCREATEX_DISP_OPEN, false);
1720 * if it's a sharing violation or we got no oplock
1721 * only keep the lock if the caller requested access
1724 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1725 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1731 } else if (!NT_STATUS_IS_OK(status)) {
1744 determine if the file size of a file can be changed,
1745 or if it is prevented by an already open file
1747 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1748 struct ntvfs_request *req,
1749 struct pvfs_filename *name,
1750 struct odb_lock **lckp)
1754 struct odb_lock *lck;
1755 uint32_t share_access;
1756 uint32_t access_mask;
1758 bool delete_on_close;
1760 status = pvfs_locking_key(name, name, &key);
1761 if (!NT_STATUS_IS_OK(status)) {
1762 return NT_STATUS_NO_MEMORY;
1765 lck = odb_lock(req, pvfs->odb_context, &key);
1767 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1768 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1771 share_access = NTCREATEX_SHARE_ACCESS_READ |
1772 NTCREATEX_SHARE_ACCESS_WRITE |
1773 NTCREATEX_SHARE_ACCESS_DELETE;
1775 * I would have thought that we would need to pass
1776 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1778 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1779 * to set the filesize.
1783 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1784 delete_on_close = false;
1785 break_to_none = true;
1787 status = odb_can_open(lck, name->stream_id,
1788 share_access, access_mask, delete_on_close,
1789 NTCREATEX_DISP_OPEN, break_to_none);
1792 * if it's a sharing violation or we got no oplock
1793 * only keep the lock if the caller requested access
1796 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1797 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1803 } else if (!NT_STATUS_IS_OK(status)) {
1816 determine if file meta data can be accessed, or if it is prevented by an
1819 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1820 struct ntvfs_request *req,
1821 struct pvfs_filename *name)
1825 struct odb_lock *lck;
1826 uint32_t share_access;
1827 uint32_t access_mask;
1828 bool delete_on_close;
1830 status = pvfs_locking_key(name, name, &key);
1831 if (!NT_STATUS_IS_OK(status)) {
1832 return NT_STATUS_NO_MEMORY;
1835 lck = odb_lock(req, pvfs->odb_context, &key);
1837 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1838 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1841 share_access = NTCREATEX_SHARE_ACCESS_READ |
1842 NTCREATEX_SHARE_ACCESS_WRITE;
1843 access_mask = SEC_FILE_READ_ATTRIBUTE;
1844 delete_on_close = false;
1846 status = odb_can_open(lck, name->stream_id,
1847 share_access, access_mask, delete_on_close,
1848 NTCREATEX_DISP_OPEN, false);
1850 if (!NT_STATUS_IS_OK(status)) {
1859 determine if delete on close is set on
1861 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1866 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1868 if (!NT_STATUS_IS_OK(status)) {
1869 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1873 return del_on_close;