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 /* support initial alloc sizes */
638 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
639 name->dos.attrib = attrib;
640 status = pvfs_dosattrib_save(pvfs, name, fd);
641 if (!NT_STATUS_IS_OK(status)) {
646 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
647 if (!NT_STATUS_IS_OK(status)) {
651 /* form the lock context used for byte range locking and
653 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
654 if (!NT_STATUS_IS_OK(status)) {
658 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
659 if (!NT_STATUS_IS_OK(status)) {
663 /* grab a lock on the open file record */
664 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
666 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
668 /* we were supposed to do a blocking lock, so something
670 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
674 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
677 del_on_close = false;
680 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
681 oplock_level = OPLOCK_NONE;
682 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
683 oplock_level = OPLOCK_BATCH;
684 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
685 oplock_level = OPLOCK_EXCLUSIVE;
688 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
689 allow_level_II_oplock = true;
692 status = odb_can_open(lck, name->stream_id,
693 share_access, access_mask, del_on_close,
694 io->generic.in.open_disposition, false);
695 if (!NT_STATUS_IS_OK(status)) {
697 /* bad news, we must have hit a race - we don't delete the file
698 here as the most likely scenario is that someone else created
699 the file at the same time */
706 f->pending_list = NULL;
708 f->share_access = io->generic.in.share_access;
709 f->access_mask = access_mask;
710 f->impersonation = io->generic.in.impersonation;
711 f->notify_buffer = NULL;
714 f->handle->pvfs = pvfs;
715 f->handle->name = talloc_steal(f->handle, name);
717 f->handle->create_options = io->generic.in.create_options;
718 f->handle->seek_offset = 0;
719 f->handle->position = 0;
721 f->handle->oplock = NULL;
722 f->handle->have_opendb_entry = true;
723 f->handle->open_completed = false;
725 status = odb_open_file(lck, f->handle, name->full_name,
726 &f->handle->fd, allow_level_II_oplock,
727 oplock_level, &oplock_granted);
729 if (!NT_STATUS_IS_OK(status)) {
730 /* bad news, we must have hit a race - we don't delete the file
731 here as the most likely scenario is that someone else created
732 the file at the same time */
737 DLIST_ADD(pvfs->files.list, f);
739 /* setup a destructor to avoid file descriptor leaks on
740 abnormal termination */
741 talloc_set_destructor(f, pvfs_fnum_destructor);
742 talloc_set_destructor(f->handle, pvfs_handle_destructor);
744 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
745 oplock_granted = OPLOCK_BATCH;
746 } else if (oplock_granted != OPLOCK_NONE) {
747 status = pvfs_setup_oplock(f, oplock_granted);
748 if (!NT_STATUS_IS_OK(status)) {
753 io->generic.out.oplock_level = oplock_granted;
754 io->generic.out.file.ntvfs = f->ntvfs;
755 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
756 io->generic.out.create_time = name->dos.create_time;
757 io->generic.out.access_time = name->dos.access_time;
758 io->generic.out.write_time = name->dos.write_time;
759 io->generic.out.change_time = name->dos.change_time;
760 io->generic.out.attrib = name->dos.attrib;
761 io->generic.out.alloc_size = name->dos.alloc_size;
762 io->generic.out.size = name->st.st_size;
763 io->generic.out.file_type = FILE_TYPE_DISK;
764 io->generic.out.ipc_state = 0;
765 io->generic.out.is_directory = 0;
767 /* success - keep the file handle */
768 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
769 if (!NT_STATUS_IS_OK(status)) {
773 f->handle->open_completed = true;
775 notify_trigger(pvfs->notify_context,
777 FILE_NOTIFY_CHANGE_FILE_NAME,
784 unlink(name->full_name);
789 state of a pending retry
791 struct pvfs_odb_retry {
792 struct ntvfs_module_context *ntvfs;
793 struct ntvfs_request *req;
794 DATA_BLOB odb_locking_key;
797 void (*callback)(struct pvfs_odb_retry *r,
798 struct ntvfs_module_context *ntvfs,
799 struct ntvfs_request *req,
802 enum pvfs_wait_notice reason);
805 /* destroy a pending request */
806 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
808 struct pvfs_state *pvfs = r->ntvfs->private_data;
809 if (r->odb_locking_key.data) {
810 struct odb_lock *lck;
811 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
813 odb_remove_pending(lck, r);
820 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
822 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
824 if (reason == PVFS_WAIT_EVENT) {
826 * The pending odb entry is already removed.
827 * We use a null locking key to indicate this
830 data_blob_free(&r->odb_locking_key);
833 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
837 setup for a retry of a request that was rejected
840 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
841 struct ntvfs_request *req,
842 struct odb_lock *lck,
843 struct timeval end_time,
846 void (*callback)(struct pvfs_odb_retry *r,
847 struct ntvfs_module_context *ntvfs,
848 struct ntvfs_request *req,
851 enum pvfs_wait_notice reason))
853 struct pvfs_state *pvfs = ntvfs->private_data;
854 struct pvfs_odb_retry *r;
855 struct pvfs_wait *wait_handle;
858 r = talloc(req, struct pvfs_odb_retry);
859 NT_STATUS_HAVE_NO_MEMORY(r);
864 r->private_data = private_data;
865 r->callback = callback;
866 r->odb_locking_key = odb_get_key(r, lck);
867 if (r->odb_locking_key.data == NULL) {
868 return NT_STATUS_NO_MEMORY;
871 /* setup a pending lock */
872 status = odb_open_file_pending(lck, r);
873 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
875 * maybe only a unix application
878 data_blob_free(&r->odb_locking_key);
879 } else if (!NT_STATUS_IS_OK(status)) {
885 talloc_set_destructor(r, pvfs_odb_retry_destructor);
887 wait_handle = pvfs_wait_message(pvfs, req,
888 MSG_PVFS_RETRY_OPEN, end_time,
889 pvfs_odb_retry_callback, r);
890 if (wait_handle == NULL) {
891 return NT_STATUS_NO_MEMORY;
894 talloc_steal(r, wait_handle);
900 retry an open after a sharing violation
902 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
903 struct ntvfs_module_context *ntvfs,
904 struct ntvfs_request *req,
907 enum pvfs_wait_notice reason)
909 union smb_open *io = talloc_get_type(_io, union smb_open);
910 struct timeval *final_timeout = NULL;
914 final_timeout = talloc_get_type(private_data,
918 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
919 just a bug in their server, but we better do the same */
920 if (reason == PVFS_WAIT_CANCEL) {
924 if (reason == PVFS_WAIT_TIMEOUT) {
926 !timeval_expired(final_timeout)) {
928 * we need to retry periodictly
929 * after an EAGAIN as there's
930 * no way the kernel tell us
931 * an oplock is released.
935 /* if it timed out, then give the failure
938 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
939 req->async_states->send_fn(req);
946 /* try the open again, which could trigger another retry setup
947 if it wants to, so we have to unmark the async flag so we
948 will know if it does a second async reply */
949 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
951 status = pvfs_open(ntvfs, req, io);
952 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
953 /* the 2nd try also replied async, so we don't send
958 /* re-mark it async, just in case someone up the chain does
960 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
962 /* send the reply up the chain */
963 req->async_states->status = status;
964 req->async_states->send_fn(req);
969 special handling for openx DENY_DOS semantics
971 This function attempts a reference open using an existing handle. If its allowed,
972 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
973 open processing continues.
975 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
976 struct ntvfs_request *req, union smb_open *io,
977 struct pvfs_file *f, struct odb_lock *lck)
979 struct pvfs_state *pvfs = ntvfs->private_data;
980 struct pvfs_file *f2;
981 struct pvfs_filename *name;
984 /* search for an existing open with the right parameters. Note
985 the magic ntcreatex options flag, which is set in the
986 generic mapping code. This might look ugly, but its
987 actually pretty much now w2k does it internally as well.
989 If you look at the BASE-DENYDOS test you will see that a
990 DENY_DOS is a very special case, and in the right
991 circumstances you actually get the _same_ handle back
992 twice, rather than a new handle.
994 for (f2=pvfs->files.list;f2;f2=f2->next) {
996 f2->ntvfs->session_info == req->session_info &&
997 f2->ntvfs->smbpid == req->smbpid &&
998 (f2->handle->create_options &
999 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
1000 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
1001 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1002 strcasecmp_m(f2->handle->name->original_name,
1003 io->generic.in.fname)==0) {
1009 return NT_STATUS_SHARING_VIOLATION;
1012 /* quite an insane set of semantics ... */
1013 if (is_exe_filename(io->generic.in.fname) &&
1014 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1015 return NT_STATUS_SHARING_VIOLATION;
1019 setup a reference to the existing handle
1021 talloc_free(f->handle);
1022 f->handle = talloc_reference(f, f2->handle);
1026 name = f->handle->name;
1028 io->generic.out.oplock_level = OPLOCK_NONE;
1029 io->generic.out.file.ntvfs = f->ntvfs;
1030 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1031 io->generic.out.create_time = name->dos.create_time;
1032 io->generic.out.access_time = name->dos.access_time;
1033 io->generic.out.write_time = name->dos.write_time;
1034 io->generic.out.change_time = name->dos.change_time;
1035 io->generic.out.attrib = name->dos.attrib;
1036 io->generic.out.alloc_size = name->dos.alloc_size;
1037 io->generic.out.size = name->st.st_size;
1038 io->generic.out.file_type = FILE_TYPE_DISK;
1039 io->generic.out.ipc_state = 0;
1040 io->generic.out.is_directory = 0;
1042 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1043 NT_STATUS_NOT_OK_RETURN(status);
1045 return NT_STATUS_OK;
1051 setup for a open retry after a sharing violation
1053 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1054 struct ntvfs_request *req,
1056 struct pvfs_file *f,
1057 struct odb_lock *lck,
1058 NTSTATUS parent_status)
1060 struct pvfs_state *pvfs = ntvfs->private_data;
1062 struct timeval end_time;
1063 struct timeval *final_timeout = NULL;
1065 if (io->generic.in.create_options &
1066 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1067 /* see if we can satisfy the request using the special DENY_DOS
1069 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1070 if (NT_STATUS_IS_OK(status)) {
1075 /* the retry should allocate a new file handle */
1078 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1079 end_time = timeval_add(&req->statistics.request_time,
1080 0, pvfs->sharing_violation_delay);
1081 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1082 end_time = timeval_add(&req->statistics.request_time,
1083 pvfs->oplock_break_timeout, 0);
1084 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1086 * we got EAGAIN which means a unix application
1087 * has an oplock or share mode
1089 * we retry every 4/5 of the sharing violation delay
1090 * to see if the unix application
1091 * has released the oplock or share mode.
1093 final_timeout = talloc(req, struct timeval);
1094 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1095 *final_timeout = timeval_add(&req->statistics.request_time,
1096 pvfs->oplock_break_timeout,
1098 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1099 end_time = timeval_min(final_timeout, &end_time);
1101 return NT_STATUS_INTERNAL_ERROR;
1104 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1105 final_timeout, pvfs_retry_open_sharing);
1111 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1112 struct ntvfs_request *req, union smb_open *io)
1114 struct pvfs_state *pvfs = ntvfs->private_data;
1116 struct pvfs_filename *name;
1117 struct pvfs_file *f;
1118 struct ntvfs_handle *h;
1121 struct odb_lock *lck;
1122 uint32_t create_options;
1123 uint32_t share_access;
1124 uint32_t access_mask;
1125 uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1127 bool stream_existed, stream_truncate=false;
1128 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1129 bool allow_level_II_oplock = false;
1131 /* use the generic mapping code to avoid implementing all the
1132 different open calls. */
1133 if (io->generic.level != RAW_OPEN_GENERIC &&
1134 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1135 return ntvfs_map_open(ntvfs, req, io);
1138 create_options = io->generic.in.create_options;
1139 share_access = io->generic.in.share_access;
1140 access_mask = io->generic.in.access_mask;
1142 if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1143 return NT_STATUS_INVALID_PARAMETER;
1146 /* some create options are not supported */
1147 if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1148 return NT_STATUS_NOT_SUPPORTED;
1151 /* other create options are not allowed */
1152 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1153 !(access_mask & SEC_STD_DELETE)) {
1154 return NT_STATUS_INVALID_PARAMETER;
1157 if (access_mask & SEC_MASK_INVALID) {
1158 return NT_STATUS_ACCESS_DENIED;
1161 /* what does this bit really mean?? */
1162 if (req->ctx->protocol == PROTOCOL_SMB2 &&
1163 access_mask == SEC_STD_SYNCHRONIZE) {
1164 return NT_STATUS_ACCESS_DENIED;
1167 if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1168 FILE_ATTRIBUTE_VOLUME|
1169 (~FILE_ATTRIBUTE_ALL_MASK))) {
1170 return NT_STATUS_INVALID_PARAMETER;
1173 /* we ignore some file_attr bits */
1174 io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED |
1175 FILE_ATTRIBUTE_COMPRESSED |
1176 FILE_ATTRIBUTE_REPARSE_POINT |
1177 FILE_ATTRIBUTE_SPARSE |
1178 FILE_ATTRIBUTE_NORMAL);
1180 /* resolve the cifs name to a posix name */
1181 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1182 PVFS_RESOLVE_STREAMS, &name);
1183 if (!NT_STATUS_IS_OK(status)) {
1187 /* if the client specified that it must not be a directory then
1188 check that it isn't */
1189 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1190 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1191 return NT_STATUS_FILE_IS_A_DIRECTORY;
1194 /* if the client specified that it must be a directory then
1196 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1197 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1198 return NT_STATUS_NOT_A_DIRECTORY;
1201 /* directory opens are handled separately */
1202 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1203 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1204 return pvfs_open_directory(pvfs, req, name, io);
1207 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1208 open doesn't match */
1209 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1213 switch (io->generic.in.open_disposition) {
1214 case NTCREATEX_DISP_SUPERSEDE:
1215 case NTCREATEX_DISP_OVERWRITE_IF:
1216 if (name->stream_name == NULL) {
1219 stream_truncate = true;
1221 create_action = NTCREATEX_ACTION_TRUNCATED;
1224 case NTCREATEX_DISP_OPEN:
1225 if (!name->stream_exists) {
1226 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1231 case NTCREATEX_DISP_OVERWRITE:
1232 if (!name->stream_exists) {
1233 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1235 if (name->stream_name == NULL) {
1238 stream_truncate = true;
1240 create_action = NTCREATEX_ACTION_TRUNCATED;
1243 case NTCREATEX_DISP_CREATE:
1244 if (name->stream_exists) {
1245 return NT_STATUS_OBJECT_NAME_COLLISION;
1250 case NTCREATEX_DISP_OPEN_IF:
1255 return NT_STATUS_INVALID_PARAMETER;
1258 /* handle creating a new file separately */
1259 if (!name->exists) {
1260 status = pvfs_create_file(pvfs, req, name, io);
1261 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1265 /* we've hit a race - the file was created during this call */
1266 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1270 /* try re-resolving the name */
1271 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1272 if (!NT_STATUS_IS_OK(status)) {
1275 /* fall through to a normal open */
1278 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1279 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1280 return NT_STATUS_CANNOT_DELETE;
1283 /* check the security descriptor */
1284 status = pvfs_access_check(pvfs, req, name, &access_mask);
1285 if (!NT_STATUS_IS_OK(status)) {
1289 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1290 NT_STATUS_NOT_OK_RETURN(status);
1292 f = talloc(h, struct pvfs_file);
1294 return NT_STATUS_NO_MEMORY;
1297 f->handle = talloc(f, struct pvfs_file_handle);
1298 if (f->handle == NULL) {
1299 return NT_STATUS_NO_MEMORY;
1304 f->pending_list = NULL;
1306 f->share_access = io->generic.in.share_access;
1307 f->access_mask = access_mask;
1308 f->impersonation = io->generic.in.impersonation;
1309 f->notify_buffer = NULL;
1312 f->handle->pvfs = pvfs;
1314 f->handle->name = talloc_steal(f->handle, name);
1315 f->handle->create_options = io->generic.in.create_options;
1316 f->handle->seek_offset = 0;
1317 f->handle->position = 0;
1318 f->handle->mode = 0;
1319 f->handle->oplock = NULL;
1320 f->handle->have_opendb_entry = false;
1321 f->handle->open_completed = false;
1323 /* form the lock context used for byte range locking and
1325 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1326 if (!NT_STATUS_IS_OK(status)) {
1330 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1331 if (!NT_STATUS_IS_OK(status)) {
1335 /* get a lock on this file before the actual open */
1336 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1338 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1340 /* we were supposed to do a blocking lock, so something
1342 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1345 DLIST_ADD(pvfs->files.list, f);
1347 /* setup a destructor to avoid file descriptor leaks on
1348 abnormal termination */
1349 talloc_set_destructor(f, pvfs_fnum_destructor);
1350 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1353 * Only SMB2 takes care of the delete_on_close,
1356 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1357 req->ctx->protocol == PROTOCOL_SMB2) {
1358 del_on_close = true;
1360 del_on_close = false;
1363 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1364 oplock_level = OPLOCK_NONE;
1365 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1366 oplock_level = OPLOCK_BATCH;
1367 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1368 oplock_level = OPLOCK_EXCLUSIVE;
1371 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1372 allow_level_II_oplock = true;
1375 /* see if we are allowed to open at the same time as existing opens */
1376 status = odb_can_open(lck, name->stream_id,
1377 share_access, access_mask, del_on_close,
1378 io->generic.in.open_disposition, false);
1381 * on a sharing violation we need to retry when the file is closed by
1382 * the other user, or after 1 second
1383 * on a non granted oplock we need to retry when the file is closed by
1384 * the other user, or after 30 seconds
1386 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1387 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1388 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1389 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1392 if (!NT_STATUS_IS_OK(status)) {
1397 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1403 /* do the actual open */
1404 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1406 status = pvfs_map_errno(f->pvfs, errno);
1409 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1411 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1412 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1413 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1422 /* now really mark the file as open */
1423 status = odb_open_file(lck, f->handle, name->full_name,
1424 &f->handle->fd, allow_level_II_oplock,
1425 oplock_level, &oplock_granted);
1427 if (!NT_STATUS_IS_OK(status)) {
1432 f->handle->have_opendb_entry = true;
1434 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1435 oplock_granted = OPLOCK_BATCH;
1436 } else if (oplock_granted != OPLOCK_NONE) {
1437 status = pvfs_setup_oplock(f, oplock_granted);
1438 if (!NT_STATUS_IS_OK(status)) {
1444 stream_existed = name->stream_exists;
1446 /* if this was a stream create then create the stream as well */
1447 if (!name->stream_exists) {
1448 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1449 if (!NT_STATUS_IS_OK(status)) {
1453 if (stream_truncate) {
1454 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1455 if (!NT_STATUS_IS_OK(status)) {
1462 /* re-resolve the open fd */
1463 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1464 if (!NT_STATUS_IS_OK(status)) {
1469 if (f->handle->name->stream_id == 0 &&
1470 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1471 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1472 /* for overwrite we need to replace file permissions */
1473 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1474 mode_t mode = pvfs_fileperms(pvfs, attrib);
1475 if (fchmod(fd, mode) == -1) {
1477 return pvfs_map_errno(pvfs, errno);
1479 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1480 name->dos.attrib = attrib;
1481 status = pvfs_dosattrib_save(pvfs, name, fd);
1482 if (!NT_STATUS_IS_OK(status)) {
1490 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1491 NT_STATUS_NOT_OK_RETURN(status);
1493 /* mark the open as having completed fully, so delete on close
1495 f->handle->open_completed = true;
1497 io->generic.out.oplock_level = oplock_granted;
1498 io->generic.out.file.ntvfs = h;
1499 io->generic.out.create_action = stream_existed?
1500 create_action:NTCREATEX_ACTION_CREATED;
1502 io->generic.out.create_time = name->dos.create_time;
1503 io->generic.out.access_time = name->dos.access_time;
1504 io->generic.out.write_time = name->dos.write_time;
1505 io->generic.out.change_time = name->dos.change_time;
1506 io->generic.out.attrib = name->dos.attrib;
1507 io->generic.out.alloc_size = name->dos.alloc_size;
1508 io->generic.out.size = name->st.st_size;
1509 io->generic.out.file_type = FILE_TYPE_DISK;
1510 io->generic.out.ipc_state = 0;
1511 io->generic.out.is_directory = 0;
1513 return NT_STATUS_OK;
1520 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1521 struct ntvfs_request *req, union smb_close *io)
1523 struct pvfs_state *pvfs = ntvfs->private_data;
1524 struct pvfs_file *f;
1525 struct utimbuf unix_times;
1527 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1528 return NT_STATUS_DOS(ERRSRV, ERRerror);
1531 if (io->generic.level != RAW_CLOSE_GENERIC) {
1532 return ntvfs_map_close(ntvfs, req, io);
1535 f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1537 return NT_STATUS_INVALID_HANDLE;
1540 if (!null_time(io->generic.in.write_time)) {
1541 unix_times.actime = 0;
1542 unix_times.modtime = io->close.in.write_time;
1543 utime(f->handle->name->full_name, &unix_times);
1546 if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1547 struct pvfs_filename *name;
1549 struct pvfs_file_handle *h = f->handle;
1551 status = pvfs_resolve_name_handle(pvfs, h);
1552 if (!NT_STATUS_IS_OK(status)) {
1557 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1558 io->generic.out.create_time = name->dos.create_time;
1559 io->generic.out.access_time = name->dos.access_time;
1560 io->generic.out.write_time = name->dos.write_time;
1561 io->generic.out.change_time = name->dos.change_time;
1562 io->generic.out.alloc_size = name->dos.alloc_size;
1563 io->generic.out.size = name->st.st_size;
1564 io->generic.out.file_attr = name->dos.attrib;
1566 ZERO_STRUCT(io->generic.out);
1571 return NT_STATUS_OK;
1576 logoff - close all file descriptors open by a vuid
1578 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1579 struct ntvfs_request *req)
1581 struct pvfs_state *pvfs = ntvfs->private_data;
1582 struct pvfs_file *f, *next;
1584 for (f=pvfs->files.list;f;f=next) {
1586 if (f->ntvfs->session_info == req->session_info) {
1591 return NT_STATUS_OK;
1596 exit - close files for the current pid
1598 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1599 struct ntvfs_request *req)
1601 struct pvfs_state *pvfs = ntvfs->private_data;
1602 struct pvfs_file *f, *next;
1604 for (f=pvfs->files.list;f;f=next) {
1606 if (f->ntvfs->session_info == req->session_info &&
1607 f->ntvfs->smbpid == req->smbpid) {
1612 return NT_STATUS_OK;
1617 change the delete on close flag on an already open file
1619 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1620 struct ntvfs_request *req,
1621 struct pvfs_file *f, bool del_on_close)
1623 struct odb_lock *lck;
1626 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1627 return NT_STATUS_CANNOT_DELETE;
1630 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1631 !pvfs_directory_empty(pvfs, f->handle->name)) {
1632 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1636 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1638 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1641 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1643 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1646 status = odb_set_delete_on_close(lck, del_on_close);
1655 determine if a file can be deleted, or if it is prevented by an
1658 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1659 struct ntvfs_request *req,
1660 struct pvfs_filename *name,
1661 struct odb_lock **lckp)
1665 struct odb_lock *lck;
1666 uint32_t share_access;
1667 uint32_t access_mask;
1668 bool delete_on_close;
1670 status = pvfs_locking_key(name, name, &key);
1671 if (!NT_STATUS_IS_OK(status)) {
1672 return NT_STATUS_NO_MEMORY;
1675 lck = odb_lock(req, pvfs->odb_context, &key);
1677 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1678 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1681 share_access = NTCREATEX_SHARE_ACCESS_READ |
1682 NTCREATEX_SHARE_ACCESS_WRITE |
1683 NTCREATEX_SHARE_ACCESS_DELETE;
1684 access_mask = SEC_STD_DELETE;
1685 delete_on_close = true;
1687 status = odb_can_open(lck, name->stream_id,
1688 share_access, access_mask, delete_on_close,
1689 NTCREATEX_DISP_OPEN, false);
1691 if (NT_STATUS_IS_OK(status)) {
1692 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1696 * if it's a sharing violation or we got no oplock
1697 * only keep the lock if the caller requested access
1700 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1701 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1707 } else if (!NT_STATUS_IS_OK(status)) {
1720 determine if a file can be renamed, or if it is prevented by an
1723 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1724 struct ntvfs_request *req,
1725 struct pvfs_filename *name,
1726 struct odb_lock **lckp)
1730 struct odb_lock *lck;
1731 uint32_t share_access;
1732 uint32_t access_mask;
1733 bool delete_on_close;
1735 status = pvfs_locking_key(name, name, &key);
1736 if (!NT_STATUS_IS_OK(status)) {
1737 return NT_STATUS_NO_MEMORY;
1740 lck = odb_lock(req, pvfs->odb_context, &key);
1742 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1743 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1746 share_access = NTCREATEX_SHARE_ACCESS_READ |
1747 NTCREATEX_SHARE_ACCESS_WRITE;
1748 access_mask = SEC_STD_DELETE;
1749 delete_on_close = false;
1751 status = odb_can_open(lck, name->stream_id,
1752 share_access, access_mask, delete_on_close,
1753 NTCREATEX_DISP_OPEN, false);
1756 * if it's a sharing violation or we got no oplock
1757 * only keep the lock if the caller requested access
1760 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1761 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1767 } else if (!NT_STATUS_IS_OK(status)) {
1780 determine if the file size of a file can be changed,
1781 or if it is prevented by an already open file
1783 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1784 struct ntvfs_request *req,
1785 struct pvfs_filename *name,
1786 struct odb_lock **lckp)
1790 struct odb_lock *lck;
1791 uint32_t share_access;
1792 uint32_t access_mask;
1794 bool delete_on_close;
1796 status = pvfs_locking_key(name, name, &key);
1797 if (!NT_STATUS_IS_OK(status)) {
1798 return NT_STATUS_NO_MEMORY;
1801 lck = odb_lock(req, pvfs->odb_context, &key);
1803 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1804 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1807 share_access = NTCREATEX_SHARE_ACCESS_READ |
1808 NTCREATEX_SHARE_ACCESS_WRITE |
1809 NTCREATEX_SHARE_ACCESS_DELETE;
1811 * I would have thought that we would need to pass
1812 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1814 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1815 * to set the filesize.
1819 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1820 delete_on_close = false;
1821 break_to_none = true;
1823 status = odb_can_open(lck, name->stream_id,
1824 share_access, access_mask, delete_on_close,
1825 NTCREATEX_DISP_OPEN, break_to_none);
1828 * if it's a sharing violation or we got no oplock
1829 * only keep the lock if the caller requested access
1832 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1833 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1839 } else if (!NT_STATUS_IS_OK(status)) {
1852 determine if file meta data can be accessed, or if it is prevented by an
1855 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1856 struct ntvfs_request *req,
1857 struct pvfs_filename *name)
1861 struct odb_lock *lck;
1862 uint32_t share_access;
1863 uint32_t access_mask;
1864 bool delete_on_close;
1866 status = pvfs_locking_key(name, name, &key);
1867 if (!NT_STATUS_IS_OK(status)) {
1868 return NT_STATUS_NO_MEMORY;
1871 lck = odb_lock(req, pvfs->odb_context, &key);
1873 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1874 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1877 share_access = NTCREATEX_SHARE_ACCESS_READ |
1878 NTCREATEX_SHARE_ACCESS_WRITE;
1879 access_mask = SEC_FILE_READ_ATTRIBUTE;
1880 delete_on_close = false;
1882 status = odb_can_open(lck, name->stream_id,
1883 share_access, access_mask, delete_on_close,
1884 NTCREATEX_DISP_OPEN, false);
1886 if (!NT_STATUS_IS_OK(status)) {
1895 determine if delete on close is set on
1897 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1902 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1904 if (!NT_STATUS_IS_OK(status)) {
1905 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1909 return del_on_close;