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;
1126 bool stream_existed, stream_truncate=false;
1127 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1128 bool allow_level_II_oplock = false;
1130 /* use the generic mapping code to avoid implementing all the
1131 different open calls. */
1132 if (io->generic.level != RAW_OPEN_GENERIC &&
1133 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1134 return ntvfs_map_open(ntvfs, req, io);
1137 create_options = io->generic.in.create_options;
1138 share_access = io->generic.in.share_access;
1139 access_mask = io->generic.in.access_mask;
1141 if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1142 return NT_STATUS_INVALID_PARAMETER;
1145 /* some create options are not supported */
1146 if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1147 return NT_STATUS_NOT_SUPPORTED;
1150 /* other create options are not allowed */
1151 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1152 !(access_mask & SEC_STD_DELETE)) {
1153 return NT_STATUS_INVALID_PARAMETER;
1156 if (access_mask & SEC_MASK_INVALID) {
1157 return NT_STATUS_ACCESS_DENIED;
1160 /* what does this bit really mean?? */
1161 if (req->ctx->protocol == PROTOCOL_SMB2 &&
1162 access_mask == SEC_STD_SYNCHRONIZE) {
1163 return NT_STATUS_ACCESS_DENIED;
1166 if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1167 FILE_ATTRIBUTE_VOLUME|
1168 (~FILE_ATTRIBUTE_ALL_MASK))) {
1169 return NT_STATUS_INVALID_PARAMETER;
1172 /* resolve the cifs name to a posix name */
1173 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1174 PVFS_RESOLVE_STREAMS, &name);
1175 if (!NT_STATUS_IS_OK(status)) {
1179 /* if the client specified that it must not be a directory then
1180 check that it isn't */
1181 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1182 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1183 return NT_STATUS_FILE_IS_A_DIRECTORY;
1186 /* if the client specified that it must be a directory then
1188 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1189 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1190 return NT_STATUS_NOT_A_DIRECTORY;
1193 /* directory opens are handled separately */
1194 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1195 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1196 return pvfs_open_directory(pvfs, req, name, io);
1199 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1200 open doesn't match */
1201 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1205 switch (io->generic.in.open_disposition) {
1206 case NTCREATEX_DISP_SUPERSEDE:
1207 case NTCREATEX_DISP_OVERWRITE_IF:
1208 if (name->stream_name == NULL) {
1211 stream_truncate = true;
1215 case NTCREATEX_DISP_OPEN:
1216 if (!name->stream_exists) {
1217 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1222 case NTCREATEX_DISP_OVERWRITE:
1223 if (!name->stream_exists) {
1224 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1226 if (name->stream_name == NULL) {
1229 stream_truncate = true;
1233 case NTCREATEX_DISP_CREATE:
1234 if (name->stream_exists) {
1235 return NT_STATUS_OBJECT_NAME_COLLISION;
1240 case NTCREATEX_DISP_OPEN_IF:
1245 return NT_STATUS_INVALID_PARAMETER;
1248 /* handle creating a new file separately */
1249 if (!name->exists) {
1250 status = pvfs_create_file(pvfs, req, name, io);
1251 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1255 /* we've hit a race - the file was created during this call */
1256 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1260 /* try re-resolving the name */
1261 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1262 if (!NT_STATUS_IS_OK(status)) {
1265 /* fall through to a normal open */
1268 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1269 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1270 return NT_STATUS_CANNOT_DELETE;
1273 /* check the security descriptor */
1274 status = pvfs_access_check(pvfs, req, name, &access_mask);
1275 if (!NT_STATUS_IS_OK(status)) {
1279 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1280 NT_STATUS_NOT_OK_RETURN(status);
1282 f = talloc(h, struct pvfs_file);
1284 return NT_STATUS_NO_MEMORY;
1287 f->handle = talloc(f, struct pvfs_file_handle);
1288 if (f->handle == NULL) {
1289 return NT_STATUS_NO_MEMORY;
1294 f->pending_list = NULL;
1296 f->share_access = io->generic.in.share_access;
1297 f->access_mask = access_mask;
1298 f->impersonation = io->generic.in.impersonation;
1299 f->notify_buffer = NULL;
1302 f->handle->pvfs = pvfs;
1304 f->handle->name = talloc_steal(f->handle, name);
1305 f->handle->create_options = io->generic.in.create_options;
1306 f->handle->seek_offset = 0;
1307 f->handle->position = 0;
1308 f->handle->mode = 0;
1309 f->handle->oplock = NULL;
1310 f->handle->have_opendb_entry = false;
1311 f->handle->open_completed = false;
1313 /* form the lock context used for byte range locking and
1315 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1316 if (!NT_STATUS_IS_OK(status)) {
1320 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1321 if (!NT_STATUS_IS_OK(status)) {
1325 /* get a lock on this file before the actual open */
1326 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1328 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1330 /* we were supposed to do a blocking lock, so something
1332 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1335 DLIST_ADD(pvfs->files.list, f);
1337 /* setup a destructor to avoid file descriptor leaks on
1338 abnormal termination */
1339 talloc_set_destructor(f, pvfs_fnum_destructor);
1340 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1343 * Only SMB2 takes care of the delete_on_close,
1346 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1347 req->ctx->protocol == PROTOCOL_SMB2) {
1348 del_on_close = true;
1350 del_on_close = false;
1353 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1354 oplock_level = OPLOCK_NONE;
1355 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1356 oplock_level = OPLOCK_BATCH;
1357 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1358 oplock_level = OPLOCK_EXCLUSIVE;
1361 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1362 allow_level_II_oplock = true;
1365 /* see if we are allowed to open at the same time as existing opens */
1366 status = odb_can_open(lck, name->stream_id,
1367 share_access, access_mask, del_on_close,
1368 io->generic.in.open_disposition, false);
1371 * on a sharing violation we need to retry when the file is closed by
1372 * the other user, or after 1 second
1373 * on a non granted oplock we need to retry when the file is closed by
1374 * the other user, or after 30 seconds
1376 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1377 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1378 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1379 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1382 if (!NT_STATUS_IS_OK(status)) {
1387 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1393 /* do the actual open */
1394 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1396 status = pvfs_map_errno(f->pvfs, errno);
1399 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1401 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1402 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1403 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1412 /* now really mark the file as open */
1413 status = odb_open_file(lck, f->handle, name->full_name,
1414 &f->handle->fd, allow_level_II_oplock,
1415 oplock_level, &oplock_granted);
1417 if (!NT_STATUS_IS_OK(status)) {
1422 f->handle->have_opendb_entry = true;
1424 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1425 oplock_granted = OPLOCK_BATCH;
1426 } else if (oplock_granted != OPLOCK_NONE) {
1427 status = pvfs_setup_oplock(f, oplock_granted);
1428 if (!NT_STATUS_IS_OK(status)) {
1434 stream_existed = name->stream_exists;
1436 /* if this was a stream create then create the stream as well */
1437 if (!name->stream_exists) {
1438 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1439 if (!NT_STATUS_IS_OK(status)) {
1443 if (stream_truncate) {
1444 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1445 if (!NT_STATUS_IS_OK(status)) {
1452 /* re-resolve the open fd */
1453 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1454 if (!NT_STATUS_IS_OK(status)) {
1459 if (f->handle->name->stream_id == 0 &&
1460 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1461 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1462 /* for overwrite we need to replace file permissions */
1463 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1464 mode_t mode = pvfs_fileperms(pvfs, attrib);
1465 if (fchmod(fd, mode) == -1) {
1467 return pvfs_map_errno(pvfs, errno);
1469 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1470 name->dos.attrib = attrib;
1471 status = pvfs_dosattrib_save(pvfs, name, fd);
1472 if (!NT_STATUS_IS_OK(status)) {
1480 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1481 NT_STATUS_NOT_OK_RETURN(status);
1483 /* mark the open as having completed fully, so delete on close
1485 f->handle->open_completed = true;
1487 io->generic.out.oplock_level = oplock_granted;
1488 io->generic.out.file.ntvfs = h;
1489 io->generic.out.create_action = stream_existed?
1490 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1491 io->generic.out.create_time = name->dos.create_time;
1492 io->generic.out.access_time = name->dos.access_time;
1493 io->generic.out.write_time = name->dos.write_time;
1494 io->generic.out.change_time = name->dos.change_time;
1495 io->generic.out.attrib = name->dos.attrib;
1496 io->generic.out.alloc_size = name->dos.alloc_size;
1497 io->generic.out.size = name->st.st_size;
1498 io->generic.out.file_type = FILE_TYPE_DISK;
1499 io->generic.out.ipc_state = 0;
1500 io->generic.out.is_directory = 0;
1502 return NT_STATUS_OK;
1509 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1510 struct ntvfs_request *req, union smb_close *io)
1512 struct pvfs_state *pvfs = ntvfs->private_data;
1513 struct pvfs_file *f;
1514 struct utimbuf unix_times;
1516 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1517 return NT_STATUS_DOS(ERRSRV, ERRerror);
1520 if (io->generic.level != RAW_CLOSE_GENERIC) {
1521 return ntvfs_map_close(ntvfs, req, io);
1524 f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1526 return NT_STATUS_INVALID_HANDLE;
1529 if (!null_time(io->generic.in.write_time)) {
1530 unix_times.actime = 0;
1531 unix_times.modtime = io->close.in.write_time;
1532 utime(f->handle->name->full_name, &unix_times);
1535 if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1536 struct pvfs_filename *name;
1538 struct pvfs_file_handle *h = f->handle;
1540 status = pvfs_resolve_name_handle(pvfs, h);
1541 if (!NT_STATUS_IS_OK(status)) {
1546 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1547 io->generic.out.create_time = name->dos.create_time;
1548 io->generic.out.access_time = name->dos.access_time;
1549 io->generic.out.write_time = name->dos.write_time;
1550 io->generic.out.change_time = name->dos.change_time;
1551 io->generic.out.alloc_size = name->dos.alloc_size;
1552 io->generic.out.size = name->st.st_size;
1553 io->generic.out.file_attr = name->dos.attrib;
1555 ZERO_STRUCT(io->generic.out);
1560 return NT_STATUS_OK;
1565 logoff - close all file descriptors open by a vuid
1567 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1568 struct ntvfs_request *req)
1570 struct pvfs_state *pvfs = ntvfs->private_data;
1571 struct pvfs_file *f, *next;
1573 for (f=pvfs->files.list;f;f=next) {
1575 if (f->ntvfs->session_info == req->session_info) {
1580 return NT_STATUS_OK;
1585 exit - close files for the current pid
1587 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1588 struct ntvfs_request *req)
1590 struct pvfs_state *pvfs = ntvfs->private_data;
1591 struct pvfs_file *f, *next;
1593 for (f=pvfs->files.list;f;f=next) {
1595 if (f->ntvfs->session_info == req->session_info &&
1596 f->ntvfs->smbpid == req->smbpid) {
1601 return NT_STATUS_OK;
1606 change the delete on close flag on an already open file
1608 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1609 struct ntvfs_request *req,
1610 struct pvfs_file *f, bool del_on_close)
1612 struct odb_lock *lck;
1615 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1616 return NT_STATUS_CANNOT_DELETE;
1619 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1620 !pvfs_directory_empty(pvfs, f->handle->name)) {
1621 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1625 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1627 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1630 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1632 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1635 status = odb_set_delete_on_close(lck, del_on_close);
1644 determine if a file can be deleted, or if it is prevented by an
1647 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1648 struct ntvfs_request *req,
1649 struct pvfs_filename *name,
1650 struct odb_lock **lckp)
1654 struct odb_lock *lck;
1655 uint32_t share_access;
1656 uint32_t access_mask;
1657 bool delete_on_close;
1659 status = pvfs_locking_key(name, name, &key);
1660 if (!NT_STATUS_IS_OK(status)) {
1661 return NT_STATUS_NO_MEMORY;
1664 lck = odb_lock(req, pvfs->odb_context, &key);
1666 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1667 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1670 share_access = NTCREATEX_SHARE_ACCESS_READ |
1671 NTCREATEX_SHARE_ACCESS_WRITE |
1672 NTCREATEX_SHARE_ACCESS_DELETE;
1673 access_mask = SEC_STD_DELETE;
1674 delete_on_close = true;
1676 status = odb_can_open(lck, name->stream_id,
1677 share_access, access_mask, delete_on_close,
1678 NTCREATEX_DISP_OPEN, false);
1680 if (NT_STATUS_IS_OK(status)) {
1681 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1685 * if it's a sharing violation or we got no oplock
1686 * only keep the lock if the caller requested access
1689 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1690 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1696 } else if (!NT_STATUS_IS_OK(status)) {
1709 determine if a file can be renamed, or if it is prevented by an
1712 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1713 struct ntvfs_request *req,
1714 struct pvfs_filename *name,
1715 struct odb_lock **lckp)
1719 struct odb_lock *lck;
1720 uint32_t share_access;
1721 uint32_t access_mask;
1722 bool delete_on_close;
1724 status = pvfs_locking_key(name, name, &key);
1725 if (!NT_STATUS_IS_OK(status)) {
1726 return NT_STATUS_NO_MEMORY;
1729 lck = odb_lock(req, pvfs->odb_context, &key);
1731 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1732 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1735 share_access = NTCREATEX_SHARE_ACCESS_READ |
1736 NTCREATEX_SHARE_ACCESS_WRITE;
1737 access_mask = SEC_STD_DELETE;
1738 delete_on_close = false;
1740 status = odb_can_open(lck, name->stream_id,
1741 share_access, access_mask, delete_on_close,
1742 NTCREATEX_DISP_OPEN, false);
1745 * if it's a sharing violation or we got no oplock
1746 * only keep the lock if the caller requested access
1749 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1750 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1756 } else if (!NT_STATUS_IS_OK(status)) {
1769 determine if the file size of a file can be changed,
1770 or if it is prevented by an already open file
1772 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1773 struct ntvfs_request *req,
1774 struct pvfs_filename *name,
1775 struct odb_lock **lckp)
1779 struct odb_lock *lck;
1780 uint32_t share_access;
1781 uint32_t access_mask;
1783 bool delete_on_close;
1785 status = pvfs_locking_key(name, name, &key);
1786 if (!NT_STATUS_IS_OK(status)) {
1787 return NT_STATUS_NO_MEMORY;
1790 lck = odb_lock(req, pvfs->odb_context, &key);
1792 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1793 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1796 share_access = NTCREATEX_SHARE_ACCESS_READ |
1797 NTCREATEX_SHARE_ACCESS_WRITE |
1798 NTCREATEX_SHARE_ACCESS_DELETE;
1800 * I would have thought that we would need to pass
1801 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1803 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1804 * to set the filesize.
1808 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1809 delete_on_close = false;
1810 break_to_none = true;
1812 status = odb_can_open(lck, name->stream_id,
1813 share_access, access_mask, delete_on_close,
1814 NTCREATEX_DISP_OPEN, break_to_none);
1817 * if it's a sharing violation or we got no oplock
1818 * only keep the lock if the caller requested access
1821 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1822 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1828 } else if (!NT_STATUS_IS_OK(status)) {
1841 determine if file meta data can be accessed, or if it is prevented by an
1844 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1845 struct ntvfs_request *req,
1846 struct pvfs_filename *name)
1850 struct odb_lock *lck;
1851 uint32_t share_access;
1852 uint32_t access_mask;
1853 bool delete_on_close;
1855 status = pvfs_locking_key(name, name, &key);
1856 if (!NT_STATUS_IS_OK(status)) {
1857 return NT_STATUS_NO_MEMORY;
1860 lck = odb_lock(req, pvfs->odb_context, &key);
1862 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1863 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1866 share_access = NTCREATEX_SHARE_ACCESS_READ |
1867 NTCREATEX_SHARE_ACCESS_WRITE;
1868 access_mask = SEC_FILE_READ_ATTRIBUTE;
1869 delete_on_close = false;
1871 status = odb_can_open(lck, name->stream_id,
1872 share_access, access_mask, delete_on_close,
1873 NTCREATEX_DISP_OPEN, false);
1875 if (!NT_STATUS_IS_OK(status)) {
1884 determine if delete on close is set on
1886 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1891 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1893 if (!NT_STATUS_IS_OK(status)) {
1894 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1898 return del_on_close;