2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - open and close
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "vfs_posix.h"
24 #include "system/dir.h"
25 #include "system/time.h"
26 #include "lib/util/dlinklist.h"
27 #include "messaging/messaging.h"
28 #include "librpc/gen_ndr/xattr.h"
31 find open file handle given fnum
33 struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
34 struct ntvfs_request *req, struct ntvfs_handle *h)
39 p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs);
42 f = talloc_get_type(p, struct pvfs_file);
49 cleanup a open directory handle
51 static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
53 if (h->have_opendb_entry) {
56 const char *delete_path = NULL;
58 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
60 DEBUG(0,("Unable to lock opendb for close\n"));
64 status = odb_close_file(lck, h, &delete_path);
65 if (!NT_STATUS_IS_OK(status)) {
66 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
67 h->name->full_name, nt_errstr(status)));
70 if (h->name->stream_name == NULL && delete_path) {
71 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
72 if (!NT_STATUS_IS_OK(status)) {
73 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
74 delete_path, nt_errstr(status)));
76 if (rmdir(delete_path) != 0) {
77 DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
78 delete_path, strerror(errno)));
89 cleanup a open directory fnum
91 static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
93 DLIST_REMOVE(f->pvfs->files.list, f);
94 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
100 setup any EAs and the ACL on newly created files/directories
102 static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
103 struct ntvfs_request *req,
104 struct pvfs_filename *name,
105 int fd, struct pvfs_file *f,
110 /* setup any EAs that were asked for */
111 if (io->ntcreatex.in.ea_list) {
112 status = pvfs_setfileinfo_ea_set(pvfs, name, fd,
113 io->ntcreatex.in.ea_list->num_eas,
114 io->ntcreatex.in.ea_list->eas);
115 if (!NT_STATUS_IS_OK(status)) {
120 /* setup an initial sec_desc if requested */
121 if (io->ntcreatex.in.sec_desc) {
122 union smb_setfileinfo set;
124 * TODO: set the full ACL!
125 * - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
126 * when a SACL is present on the sd,
127 * but the user doesn't have SeSecurityPrivilege
130 set.set_secdesc.in.file.ntvfs = f->ntvfs;
131 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
132 set.set_secdesc.in.sd = io->ntcreatex.in.sec_desc;
134 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
136 /* otherwise setup an inherited acl from the parent */
137 status = pvfs_acl_inherit(pvfs, req, name, fd);
144 form the lock context used for opendb locking. Note that we must
145 zero here to take account of possible padding on some architectures
147 NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
148 TALLOC_CTX *mem_ctx, DATA_BLOB *key)
154 ZERO_STRUCT(lock_context);
156 lock_context.device = name->st.st_dev;
157 lock_context.inode = name->st.st_ino;
159 *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
160 if (key->data == NULL) {
161 return NT_STATUS_NO_MEMORY;
171 static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
172 struct ntvfs_request *req,
173 struct pvfs_filename *name,
177 struct ntvfs_handle *h;
179 uint32_t create_action;
180 uint32_t access_mask = io->generic.in.access_mask;
181 struct odb_lock *lck;
183 uint32_t create_options;
184 uint32_t share_access;
186 create_options = io->generic.in.create_options;
187 share_access = io->generic.in.share_access;
189 if (name->stream_name) {
190 return NT_STATUS_NOT_A_DIRECTORY;
193 /* if the client says it must be a directory, and it isn't,
195 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
196 return NT_STATUS_NOT_A_DIRECTORY;
199 switch (io->generic.in.open_disposition) {
200 case NTCREATEX_DISP_OPEN_IF:
203 case NTCREATEX_DISP_OPEN:
205 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
209 case NTCREATEX_DISP_CREATE:
211 return NT_STATUS_OBJECT_NAME_COLLISION;
215 case NTCREATEX_DISP_OVERWRITE_IF:
216 case NTCREATEX_DISP_OVERWRITE:
217 case NTCREATEX_DISP_SUPERSEDE:
219 return NT_STATUS_INVALID_PARAMETER;
222 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
223 NT_STATUS_NOT_OK_RETURN(status);
225 f = talloc(h, struct pvfs_file);
227 return NT_STATUS_NO_MEMORY;
230 f->handle = talloc(f, struct pvfs_file_handle);
231 if (f->handle == NULL) {
232 return NT_STATUS_NO_MEMORY;
236 /* check the security descriptor */
237 status = pvfs_access_check(pvfs, req, name, &access_mask);
239 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
241 if (!NT_STATUS_IS_OK(status)) {
247 f->pending_list = NULL;
249 f->share_access = io->generic.in.share_access;
250 f->impersonation = io->generic.in.impersonation;
251 f->access_mask = access_mask;
252 f->brl_handle = NULL;
253 f->notify_buffer = NULL;
256 f->handle->pvfs = pvfs;
257 f->handle->name = talloc_steal(f->handle, name);
259 f->handle->odb_locking_key = data_blob(NULL, 0);
260 f->handle->create_options = io->generic.in.create_options;
261 f->handle->seek_offset = 0;
262 f->handle->position = 0;
264 f->handle->oplock = NULL;
265 f->handle->open_completed = false;
267 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
268 pvfs_directory_empty(pvfs, f->handle->name)) {
271 del_on_close = false;
275 /* form the lock context used for opendb locking */
276 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
277 if (!NT_STATUS_IS_OK(status)) {
281 /* get a lock on this file before the actual open */
282 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
284 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
286 /* we were supposed to do a blocking lock, so something
288 return NT_STATUS_INTERNAL_DB_CORRUPTION;
291 /* see if we are allowed to open at the same time as existing opens */
292 status = odb_can_open(lck, name->stream_id,
293 share_access, access_mask, del_on_close,
294 io->generic.in.open_disposition, false);
295 if (!NT_STATUS_IS_OK(status)) {
300 /* now really mark the file as open */
301 status = odb_open_file(lck, f->handle, name->full_name,
302 NULL, false, OPLOCK_NONE, NULL);
304 if (!NT_STATUS_IS_OK(status)) {
309 f->handle->have_opendb_entry = true;
312 DLIST_ADD(pvfs->files.list, f);
314 /* setup destructors to avoid leaks on abnormal termination */
315 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
316 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
319 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
320 mode_t mode = pvfs_fileperms(pvfs, attrib);
322 if (mkdir(name->full_name, mode) == -1) {
323 return pvfs_map_errno(pvfs,errno);
326 pvfs_xattr_unlink_hook(pvfs, name->full_name);
328 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
329 if (!NT_STATUS_IS_OK(status)) {
333 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
334 if (!NT_STATUS_IS_OK(status)) {
338 /* form the lock context used for opendb locking */
339 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
340 if (!NT_STATUS_IS_OK(status)) {
344 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
346 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
348 /* we were supposed to do a blocking lock, so something
350 return NT_STATUS_INTERNAL_DB_CORRUPTION;
353 status = odb_can_open(lck, name->stream_id,
354 share_access, access_mask, del_on_close,
355 io->generic.in.open_disposition, false);
357 if (!NT_STATUS_IS_OK(status)) {
361 status = odb_open_file(lck, f->handle, name->full_name,
362 NULL, false, OPLOCK_NONE, NULL);
364 if (!NT_STATUS_IS_OK(status)) {
368 f->handle->have_opendb_entry = true;
370 create_action = NTCREATEX_ACTION_CREATED;
372 notify_trigger(pvfs->notify_context,
374 FILE_NOTIFY_CHANGE_DIR_NAME,
377 create_action = NTCREATEX_ACTION_EXISTED;
381 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
384 /* the open succeeded, keep this handle permanently */
385 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
386 if (!NT_STATUS_IS_OK(status)) {
390 f->handle->open_completed = true;
392 io->generic.out.oplock_level = OPLOCK_NONE;
393 io->generic.out.file.ntvfs = h;
394 io->generic.out.create_action = create_action;
395 io->generic.out.create_time = name->dos.create_time;
396 io->generic.out.access_time = name->dos.access_time;
397 io->generic.out.write_time = name->dos.write_time;
398 io->generic.out.change_time = name->dos.change_time;
399 io->generic.out.attrib = name->dos.attrib;
400 io->generic.out.alloc_size = name->dos.alloc_size;
401 io->generic.out.size = name->st.st_size;
402 io->generic.out.file_type = FILE_TYPE_DISK;
403 io->generic.out.ipc_state = 0;
404 io->generic.out.is_directory = 1;
409 rmdir(name->full_name);
414 destroy a struct pvfs_file_handle
416 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
418 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
419 h->name->stream_name) {
421 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
422 if (!NT_STATUS_IS_OK(status)) {
423 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
424 h->name->stream_name, h->name->full_name));
429 if (close(h->fd) != 0) {
430 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
431 h->fd, h->name->full_name, strerror(errno)));
436 if (h->have_opendb_entry) {
437 struct odb_lock *lck;
439 const char *delete_path = NULL;
441 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
443 DEBUG(0,("Unable to lock opendb for close\n"));
447 status = odb_close_file(lck, h, &delete_path);
448 if (!NT_STATUS_IS_OK(status)) {
449 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
450 h->name->full_name, nt_errstr(status)));
453 if (h->name->stream_name == NULL &&
454 h->open_completed && delete_path) {
455 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
456 if (!NT_STATUS_IS_OK(status)) {
457 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
458 delete_path, nt_errstr(status)));
460 if (unlink(delete_path) != 0) {
461 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
462 delete_path, strerror(errno)));
464 notify_trigger(h->pvfs->notify_context,
465 NOTIFY_ACTION_REMOVED,
466 FILE_NOTIFY_CHANGE_FILE_NAME,
479 destroy a struct pvfs_file
481 static int pvfs_fnum_destructor(struct pvfs_file *f)
483 DLIST_REMOVE(f->pvfs->files.list, f);
484 pvfs_lock_close(f->pvfs, f);
485 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
492 form the lock context used for byte range locking. This is separate
493 from the locking key used for opendb locking as it needs to take
494 account of file streams (each stream is a separate byte range
497 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
498 struct pvfs_filename *name,
499 struct ntvfs_handle *ntvfs,
500 struct brl_handle **_h)
502 DATA_BLOB odb_key, key;
504 struct brl_handle *h;
506 status = pvfs_locking_key(name, mem_ctx, &odb_key);
507 NT_STATUS_NOT_OK_RETURN(status);
509 if (name->stream_name == NULL) {
512 key = data_blob_talloc(mem_ctx, NULL,
513 odb_key.length + strlen(name->stream_name) + 1);
514 NT_STATUS_HAVE_NO_MEMORY(key.data);
515 memcpy(key.data, odb_key.data, odb_key.length);
516 memcpy(key.data + odb_key.length,
517 name->stream_name, strlen(name->stream_name) + 1);
518 data_blob_free(&odb_key);
521 h = brl_create_handle(mem_ctx, ntvfs, &key);
522 NT_STATUS_HAVE_NO_MEMORY(h);
531 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
532 struct ntvfs_request *req,
533 struct pvfs_filename *name,
538 struct ntvfs_handle *h;
540 struct odb_lock *lck;
541 uint32_t create_options = io->generic.in.create_options;
542 uint32_t share_access = io->generic.in.share_access;
543 uint32_t access_mask = io->generic.in.access_mask;
547 struct pvfs_filename *parent;
548 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
549 bool allow_level_II_oplock = false;
551 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
552 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
553 return NT_STATUS_CANNOT_DELETE;
556 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
557 NT_STATUS_NOT_OK_RETURN(status);
559 /* check that the parent isn't opened with delete on close set */
560 status = pvfs_resolve_parent(pvfs, req, name, &parent);
561 if (NT_STATUS_IS_OK(status)) {
562 DATA_BLOB locking_key;
563 status = pvfs_locking_key(parent, req, &locking_key);
564 NT_STATUS_NOT_OK_RETURN(status);
565 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key,
567 NT_STATUS_NOT_OK_RETURN(status);
569 return NT_STATUS_DELETE_PENDING;
573 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
579 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
580 NT_STATUS_NOT_OK_RETURN(status);
582 f = talloc(h, struct pvfs_file);
583 NT_STATUS_HAVE_NO_MEMORY(f);
585 f->handle = talloc(f, struct pvfs_file_handle);
586 NT_STATUS_HAVE_NO_MEMORY(f->handle);
588 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
589 mode = pvfs_fileperms(pvfs, attrib);
591 /* create the file */
592 fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
594 return pvfs_map_errno(pvfs, errno);
597 pvfs_xattr_unlink_hook(pvfs, name->full_name);
599 /* if this was a stream create then create the stream as well */
600 if (name->stream_name) {
601 status = pvfs_stream_create(pvfs, name, fd);
602 if (!NT_STATUS_IS_OK(status)) {
608 /* re-resolve the open fd */
609 status = pvfs_resolve_name_fd(pvfs, fd, name);
610 if (!NT_STATUS_IS_OK(status)) {
615 name->dos.attrib = attrib;
616 status = pvfs_dosattrib_save(pvfs, name, fd);
617 if (!NT_STATUS_IS_OK(status)) {
622 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
623 if (!NT_STATUS_IS_OK(status)) {
627 /* form the lock context used for byte range locking and
629 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
630 if (!NT_STATUS_IS_OK(status)) {
634 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
635 if (!NT_STATUS_IS_OK(status)) {
639 /* grab a lock on the open file record */
640 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
642 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
644 /* we were supposed to do a blocking lock, so something
646 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
650 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
653 del_on_close = false;
656 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
657 oplock_level = OPLOCK_NONE;
658 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
659 oplock_level = OPLOCK_BATCH;
660 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
661 oplock_level = OPLOCK_EXCLUSIVE;
664 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
665 allow_level_II_oplock = true;
668 status = odb_can_open(lck, name->stream_id,
669 share_access, access_mask, del_on_close,
670 io->generic.in.open_disposition, false);
671 if (!NT_STATUS_IS_OK(status)) {
673 /* bad news, we must have hit a race - we don't delete the file
674 here as the most likely scenario is that someone else created
675 the file at the same time */
682 f->pending_list = NULL;
684 f->share_access = io->generic.in.share_access;
685 f->access_mask = access_mask;
686 f->impersonation = io->generic.in.impersonation;
687 f->notify_buffer = NULL;
690 f->handle->pvfs = pvfs;
691 f->handle->name = talloc_steal(f->handle, name);
693 f->handle->create_options = io->generic.in.create_options;
694 f->handle->seek_offset = 0;
695 f->handle->position = 0;
697 f->handle->oplock = NULL;
698 f->handle->have_opendb_entry = true;
699 f->handle->open_completed = false;
701 status = odb_open_file(lck, f->handle, name->full_name,
702 &f->handle->fd, allow_level_II_oplock,
703 oplock_level, &oplock_granted);
705 if (!NT_STATUS_IS_OK(status)) {
706 /* bad news, we must have hit a race - we don't delete the file
707 here as the most likely scenario is that someone else created
708 the file at the same time */
713 DLIST_ADD(pvfs->files.list, f);
715 /* setup a destructor to avoid file descriptor leaks on
716 abnormal termination */
717 talloc_set_destructor(f, pvfs_fnum_destructor);
718 talloc_set_destructor(f->handle, pvfs_handle_destructor);
720 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
721 oplock_granted = OPLOCK_BATCH;
722 } else if (oplock_granted != OPLOCK_NONE) {
723 status = pvfs_setup_oplock(f, oplock_granted);
724 if (!NT_STATUS_IS_OK(status)) {
729 io->generic.out.oplock_level = oplock_granted;
730 io->generic.out.file.ntvfs = f->ntvfs;
731 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
732 io->generic.out.create_time = name->dos.create_time;
733 io->generic.out.access_time = name->dos.access_time;
734 io->generic.out.write_time = name->dos.write_time;
735 io->generic.out.change_time = name->dos.change_time;
736 io->generic.out.attrib = name->dos.attrib;
737 io->generic.out.alloc_size = name->dos.alloc_size;
738 io->generic.out.size = name->st.st_size;
739 io->generic.out.file_type = FILE_TYPE_DISK;
740 io->generic.out.ipc_state = 0;
741 io->generic.out.is_directory = 0;
743 /* success - keep the file handle */
744 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
745 if (!NT_STATUS_IS_OK(status)) {
749 f->handle->open_completed = true;
751 notify_trigger(pvfs->notify_context,
753 FILE_NOTIFY_CHANGE_FILE_NAME,
760 unlink(name->full_name);
765 state of a pending retry
767 struct pvfs_odb_retry {
768 struct ntvfs_module_context *ntvfs;
769 struct ntvfs_request *req;
770 DATA_BLOB odb_locking_key;
773 void (*callback)(struct pvfs_odb_retry *r,
774 struct ntvfs_module_context *ntvfs,
775 struct ntvfs_request *req,
778 enum pvfs_wait_notice reason);
781 /* destroy a pending request */
782 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
784 struct pvfs_state *pvfs = r->ntvfs->private_data;
785 if (r->odb_locking_key.data) {
786 struct odb_lock *lck;
787 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
789 odb_remove_pending(lck, r);
796 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
798 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
800 if (reason == PVFS_WAIT_EVENT) {
802 * The pending odb entry is already removed.
803 * We use a null locking key to indicate this
806 data_blob_free(&r->odb_locking_key);
809 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
813 setup for a retry of a request that was rejected
816 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
817 struct ntvfs_request *req,
818 struct odb_lock *lck,
819 struct timeval end_time,
822 void (*callback)(struct pvfs_odb_retry *r,
823 struct ntvfs_module_context *ntvfs,
824 struct ntvfs_request *req,
827 enum pvfs_wait_notice reason))
829 struct pvfs_state *pvfs = ntvfs->private_data;
830 struct pvfs_odb_retry *r;
831 struct pvfs_wait *wait_handle;
834 r = talloc(req, struct pvfs_odb_retry);
835 NT_STATUS_HAVE_NO_MEMORY(r);
840 r->private_data = private_data;
841 r->callback = callback;
842 r->odb_locking_key = odb_get_key(r, lck);
843 if (r->odb_locking_key.data == NULL) {
844 return NT_STATUS_NO_MEMORY;
847 /* setup a pending lock */
848 status = odb_open_file_pending(lck, r);
849 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
851 * maybe only a unix application
854 data_blob_free(&r->odb_locking_key);
855 } else if (!NT_STATUS_IS_OK(status)) {
861 talloc_set_destructor(r, pvfs_odb_retry_destructor);
863 wait_handle = pvfs_wait_message(pvfs, req,
864 MSG_PVFS_RETRY_OPEN, end_time,
865 pvfs_odb_retry_callback, r);
866 if (wait_handle == NULL) {
867 return NT_STATUS_NO_MEMORY;
870 talloc_steal(r, wait_handle);
876 retry an open after a sharing violation
878 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
879 struct ntvfs_module_context *ntvfs,
880 struct ntvfs_request *req,
883 enum pvfs_wait_notice reason)
885 union smb_open *io = talloc_get_type(_io, union smb_open);
886 struct timeval *final_timeout = NULL;
890 final_timeout = talloc_get_type(private_data,
894 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
895 just a bug in their server, but we better do the same */
896 if (reason == PVFS_WAIT_CANCEL) {
900 if (reason == PVFS_WAIT_TIMEOUT) {
902 !timeval_expired(final_timeout)) {
904 * we need to retry periodictly
905 * after an EAGAIN as there's
906 * no way the kernel tell us
907 * an oplock is released.
911 /* if it timed out, then give the failure
914 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
915 req->async_states->send_fn(req);
922 /* try the open again, which could trigger another retry setup
923 if it wants to, so we have to unmark the async flag so we
924 will know if it does a second async reply */
925 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
927 status = pvfs_open(ntvfs, req, io);
928 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
929 /* the 2nd try also replied async, so we don't send
934 /* re-mark it async, just in case someone up the chain does
936 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
938 /* send the reply up the chain */
939 req->async_states->status = status;
940 req->async_states->send_fn(req);
945 special handling for openx DENY_DOS semantics
947 This function attempts a reference open using an existing handle. If its allowed,
948 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
949 open processing continues.
951 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
952 struct ntvfs_request *req, union smb_open *io,
953 struct pvfs_file *f, struct odb_lock *lck)
955 struct pvfs_state *pvfs = ntvfs->private_data;
956 struct pvfs_file *f2;
957 struct pvfs_filename *name;
960 /* search for an existing open with the right parameters. Note
961 the magic ntcreatex options flag, which is set in the
962 generic mapping code. This might look ugly, but its
963 actually pretty much now w2k does it internally as well.
965 If you look at the BASE-DENYDOS test you will see that a
966 DENY_DOS is a very special case, and in the right
967 circumstances you actually get the _same_ handle back
968 twice, rather than a new handle.
970 for (f2=pvfs->files.list;f2;f2=f2->next) {
972 f2->ntvfs->session_info == req->session_info &&
973 f2->ntvfs->smbpid == req->smbpid &&
974 (f2->handle->create_options &
975 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
976 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
977 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
978 strcasecmp_m(f2->handle->name->original_name,
979 io->generic.in.fname)==0) {
985 return NT_STATUS_SHARING_VIOLATION;
988 /* quite an insane set of semantics ... */
989 if (is_exe_filename(io->generic.in.fname) &&
990 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
991 return NT_STATUS_SHARING_VIOLATION;
995 setup a reference to the existing handle
997 talloc_free(f->handle);
998 f->handle = talloc_reference(f, f2->handle);
1002 name = f->handle->name;
1004 io->generic.out.oplock_level = OPLOCK_NONE;
1005 io->generic.out.file.ntvfs = f->ntvfs;
1006 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1007 io->generic.out.create_time = name->dos.create_time;
1008 io->generic.out.access_time = name->dos.access_time;
1009 io->generic.out.write_time = name->dos.write_time;
1010 io->generic.out.change_time = name->dos.change_time;
1011 io->generic.out.attrib = name->dos.attrib;
1012 io->generic.out.alloc_size = name->dos.alloc_size;
1013 io->generic.out.size = name->st.st_size;
1014 io->generic.out.file_type = FILE_TYPE_DISK;
1015 io->generic.out.ipc_state = 0;
1016 io->generic.out.is_directory = 0;
1018 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1019 NT_STATUS_NOT_OK_RETURN(status);
1021 return NT_STATUS_OK;
1027 setup for a open retry after a sharing violation
1029 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1030 struct ntvfs_request *req,
1032 struct pvfs_file *f,
1033 struct odb_lock *lck,
1034 NTSTATUS parent_status)
1036 struct pvfs_state *pvfs = ntvfs->private_data;
1038 struct timeval end_time;
1039 struct timeval *final_timeout = NULL;
1041 if (io->generic.in.create_options &
1042 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1043 /* see if we can satisfy the request using the special DENY_DOS
1045 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1046 if (NT_STATUS_IS_OK(status)) {
1051 /* the retry should allocate a new file handle */
1054 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1055 end_time = timeval_add(&req->statistics.request_time,
1056 0, pvfs->sharing_violation_delay);
1057 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1058 end_time = timeval_add(&req->statistics.request_time,
1059 pvfs->oplock_break_timeout, 0);
1060 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1062 * we got EAGAIN which means a unix application
1063 * has an oplock or share mode
1065 * we retry every 4/5 of the sharing violation delay
1066 * to see if the unix application
1067 * has released the oplock or share mode.
1069 final_timeout = talloc(req, struct timeval);
1070 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1071 *final_timeout = timeval_add(&req->statistics.request_time,
1072 pvfs->oplock_break_timeout,
1074 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1075 end_time = timeval_min(final_timeout, &end_time);
1077 return NT_STATUS_INTERNAL_ERROR;
1080 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1081 final_timeout, pvfs_retry_open_sharing);
1087 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1088 struct ntvfs_request *req, union smb_open *io)
1090 struct pvfs_state *pvfs = ntvfs->private_data;
1092 struct pvfs_filename *name;
1093 struct pvfs_file *f;
1094 struct ntvfs_handle *h;
1097 struct odb_lock *lck;
1098 uint32_t create_options;
1099 uint32_t share_access;
1100 uint32_t access_mask;
1102 bool stream_existed, stream_truncate=false;
1103 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1104 bool allow_level_II_oplock = false;
1106 /* use the generic mapping code to avoid implementing all the
1107 different open calls. */
1108 if (io->generic.level != RAW_OPEN_GENERIC &&
1109 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1110 return ntvfs_map_open(ntvfs, req, io);
1113 /* resolve the cifs name to a posix name */
1114 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1115 PVFS_RESOLVE_STREAMS, &name);
1116 if (!NT_STATUS_IS_OK(status)) {
1120 /* directory opens are handled separately */
1121 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1122 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1123 return pvfs_open_directory(pvfs, req, name, io);
1126 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1127 open doesn't match */
1128 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1130 create_options = io->generic.in.create_options;
1131 share_access = io->generic.in.share_access;
1132 access_mask = io->generic.in.access_mask;
1134 /* certain create options are not allowed */
1135 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1136 !(access_mask & SEC_STD_DELETE)) {
1137 return NT_STATUS_INVALID_PARAMETER;
1142 switch (io->generic.in.open_disposition) {
1143 case NTCREATEX_DISP_SUPERSEDE:
1144 case NTCREATEX_DISP_OVERWRITE_IF:
1145 if (name->stream_name == NULL) {
1148 stream_truncate = true;
1152 case NTCREATEX_DISP_OPEN:
1153 if (!name->stream_exists) {
1154 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1159 case NTCREATEX_DISP_OVERWRITE:
1160 if (!name->stream_exists) {
1161 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1163 if (name->stream_name == NULL) {
1166 stream_truncate = true;
1170 case NTCREATEX_DISP_CREATE:
1171 if (name->stream_exists) {
1172 return NT_STATUS_OBJECT_NAME_COLLISION;
1177 case NTCREATEX_DISP_OPEN_IF:
1182 return NT_STATUS_INVALID_PARAMETER;
1185 /* handle creating a new file separately */
1186 if (!name->exists) {
1187 status = pvfs_create_file(pvfs, req, name, io);
1188 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1192 /* we've hit a race - the file was created during this call */
1193 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1197 /* try re-resolving the name */
1198 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1199 if (!NT_STATUS_IS_OK(status)) {
1202 /* fall through to a normal open */
1205 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1206 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1207 return NT_STATUS_CANNOT_DELETE;
1210 /* check the security descriptor */
1211 status = pvfs_access_check(pvfs, req, name, &access_mask);
1212 if (!NT_STATUS_IS_OK(status)) {
1216 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1217 NT_STATUS_NOT_OK_RETURN(status);
1219 f = talloc(h, struct pvfs_file);
1221 return NT_STATUS_NO_MEMORY;
1224 f->handle = talloc(f, struct pvfs_file_handle);
1225 if (f->handle == NULL) {
1226 return NT_STATUS_NO_MEMORY;
1231 f->pending_list = NULL;
1233 f->share_access = io->generic.in.share_access;
1234 f->access_mask = access_mask;
1235 f->impersonation = io->generic.in.impersonation;
1236 f->notify_buffer = NULL;
1239 f->handle->pvfs = pvfs;
1241 f->handle->name = talloc_steal(f->handle, name);
1242 f->handle->create_options = io->generic.in.create_options;
1243 f->handle->seek_offset = 0;
1244 f->handle->position = 0;
1245 f->handle->mode = 0;
1246 f->handle->oplock = NULL;
1247 f->handle->have_opendb_entry = false;
1248 f->handle->open_completed = false;
1250 /* form the lock context used for byte range locking and
1252 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1253 if (!NT_STATUS_IS_OK(status)) {
1257 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1258 if (!NT_STATUS_IS_OK(status)) {
1262 /* get a lock on this file before the actual open */
1263 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1265 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1267 /* we were supposed to do a blocking lock, so something
1269 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1272 DLIST_ADD(pvfs->files.list, f);
1274 /* setup a destructor to avoid file descriptor leaks on
1275 abnormal termination */
1276 talloc_set_destructor(f, pvfs_fnum_destructor);
1277 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1280 * Only SMB2 takes care of the delete_on_close,
1283 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1284 req->ctx->protocol == PROTOCOL_SMB2) {
1285 del_on_close = true;
1287 del_on_close = false;
1290 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1291 oplock_level = OPLOCK_NONE;
1292 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1293 oplock_level = OPLOCK_BATCH;
1294 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1295 oplock_level = OPLOCK_EXCLUSIVE;
1298 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1299 allow_level_II_oplock = true;
1302 /* see if we are allowed to open at the same time as existing opens */
1303 status = odb_can_open(lck, name->stream_id,
1304 share_access, access_mask, del_on_close,
1305 io->generic.in.open_disposition, false);
1308 * on a sharing violation we need to retry when the file is closed by
1309 * the other user, or after 1 second
1310 * on a non granted oplock we need to retry when the file is closed by
1311 * the other user, or after 30 seconds
1313 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1314 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1315 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1316 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1319 if (!NT_STATUS_IS_OK(status)) {
1324 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1330 /* do the actual open */
1331 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1333 status = pvfs_map_errno(f->pvfs, errno);
1336 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1338 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1339 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1340 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1349 /* now really mark the file as open */
1350 status = odb_open_file(lck, f->handle, name->full_name,
1351 &f->handle->fd, allow_level_II_oplock,
1352 oplock_level, &oplock_granted);
1354 if (!NT_STATUS_IS_OK(status)) {
1359 f->handle->have_opendb_entry = true;
1361 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1362 oplock_granted = OPLOCK_BATCH;
1363 } else if (oplock_granted != OPLOCK_NONE) {
1364 status = pvfs_setup_oplock(f, oplock_granted);
1365 if (!NT_STATUS_IS_OK(status)) {
1371 stream_existed = name->stream_exists;
1373 /* if this was a stream create then create the stream as well */
1374 if (!name->stream_exists) {
1375 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1376 if (!NT_STATUS_IS_OK(status)) {
1380 if (stream_truncate) {
1381 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1382 if (!NT_STATUS_IS_OK(status)) {
1389 /* re-resolve the open fd */
1390 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1391 if (!NT_STATUS_IS_OK(status)) {
1396 if (f->handle->name->stream_id == 0 &&
1397 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1398 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1399 /* for overwrite we need to replace file permissions */
1400 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1401 mode_t mode = pvfs_fileperms(pvfs, attrib);
1402 if (fchmod(fd, mode) == -1) {
1404 return pvfs_map_errno(pvfs, errno);
1406 name->dos.attrib = attrib;
1407 status = pvfs_dosattrib_save(pvfs, name, fd);
1408 if (!NT_STATUS_IS_OK(status)) {
1416 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1417 NT_STATUS_NOT_OK_RETURN(status);
1419 /* mark the open as having completed fully, so delete on close
1421 f->handle->open_completed = true;
1423 io->generic.out.oplock_level = oplock_granted;
1424 io->generic.out.file.ntvfs = h;
1425 io->generic.out.create_action = stream_existed?
1426 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1427 io->generic.out.create_time = name->dos.create_time;
1428 io->generic.out.access_time = name->dos.access_time;
1429 io->generic.out.write_time = name->dos.write_time;
1430 io->generic.out.change_time = name->dos.change_time;
1431 io->generic.out.attrib = name->dos.attrib;
1432 io->generic.out.alloc_size = name->dos.alloc_size;
1433 io->generic.out.size = name->st.st_size;
1434 io->generic.out.file_type = FILE_TYPE_DISK;
1435 io->generic.out.ipc_state = 0;
1436 io->generic.out.is_directory = 0;
1438 return NT_STATUS_OK;
1445 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1446 struct ntvfs_request *req, union smb_close *io)
1448 struct pvfs_state *pvfs = ntvfs->private_data;
1449 struct pvfs_file *f;
1450 struct utimbuf unix_times;
1452 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1453 return NT_STATUS_DOS(ERRSRV, ERRerror);
1456 if (io->generic.level != RAW_CLOSE_CLOSE) {
1457 return ntvfs_map_close(ntvfs, req, io);
1460 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1462 return NT_STATUS_INVALID_HANDLE;
1465 if (!null_time(io->close.in.write_time)) {
1466 unix_times.actime = 0;
1467 unix_times.modtime = io->close.in.write_time;
1468 utime(f->handle->name->full_name, &unix_times);
1473 return NT_STATUS_OK;
1478 logoff - close all file descriptors open by a vuid
1480 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1481 struct ntvfs_request *req)
1483 struct pvfs_state *pvfs = ntvfs->private_data;
1484 struct pvfs_file *f, *next;
1486 for (f=pvfs->files.list;f;f=next) {
1488 if (f->ntvfs->session_info == req->session_info) {
1493 return NT_STATUS_OK;
1498 exit - close files for the current pid
1500 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1501 struct ntvfs_request *req)
1503 struct pvfs_state *pvfs = ntvfs->private_data;
1504 struct pvfs_file *f, *next;
1506 for (f=pvfs->files.list;f;f=next) {
1508 if (f->ntvfs->session_info == req->session_info &&
1509 f->ntvfs->smbpid == req->smbpid) {
1514 return NT_STATUS_OK;
1519 change the delete on close flag on an already open file
1521 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1522 struct ntvfs_request *req,
1523 struct pvfs_file *f, bool del_on_close)
1525 struct odb_lock *lck;
1528 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1529 return NT_STATUS_CANNOT_DELETE;
1532 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1533 !pvfs_directory_empty(pvfs, f->handle->name)) {
1534 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1538 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1540 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1543 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1545 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1548 status = odb_set_delete_on_close(lck, del_on_close);
1557 determine if a file can be deleted, or if it is prevented by an
1560 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1561 struct ntvfs_request *req,
1562 struct pvfs_filename *name,
1563 struct odb_lock **lckp)
1567 struct odb_lock *lck;
1568 uint32_t share_access;
1569 uint32_t access_mask;
1570 bool delete_on_close;
1572 status = pvfs_locking_key(name, name, &key);
1573 if (!NT_STATUS_IS_OK(status)) {
1574 return NT_STATUS_NO_MEMORY;
1577 lck = odb_lock(req, pvfs->odb_context, &key);
1579 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1580 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1583 share_access = NTCREATEX_SHARE_ACCESS_READ |
1584 NTCREATEX_SHARE_ACCESS_WRITE |
1585 NTCREATEX_SHARE_ACCESS_DELETE;
1586 access_mask = SEC_STD_DELETE;
1587 delete_on_close = true;
1589 status = odb_can_open(lck, name->stream_id,
1590 share_access, access_mask, delete_on_close,
1591 NTCREATEX_DISP_OPEN, false);
1593 if (NT_STATUS_IS_OK(status)) {
1594 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1598 * if it's a sharing violation or we got no oplock
1599 * only keep the lock if the caller requested access
1602 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1603 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1609 } else if (!NT_STATUS_IS_OK(status)) {
1622 determine if a file can be renamed, or if it is prevented by an
1625 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1626 struct ntvfs_request *req,
1627 struct pvfs_filename *name,
1628 struct odb_lock **lckp)
1632 struct odb_lock *lck;
1633 uint32_t share_access;
1634 uint32_t access_mask;
1635 bool delete_on_close;
1637 status = pvfs_locking_key(name, name, &key);
1638 if (!NT_STATUS_IS_OK(status)) {
1639 return NT_STATUS_NO_MEMORY;
1642 lck = odb_lock(req, pvfs->odb_context, &key);
1644 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1645 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1648 share_access = NTCREATEX_SHARE_ACCESS_READ |
1649 NTCREATEX_SHARE_ACCESS_WRITE;
1650 access_mask = SEC_STD_DELETE;
1651 delete_on_close = false;
1653 status = odb_can_open(lck, name->stream_id,
1654 share_access, access_mask, delete_on_close,
1655 NTCREATEX_DISP_OPEN, false);
1658 * if it's a sharing violation or we got no oplock
1659 * only keep the lock if the caller requested access
1662 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1663 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1669 } else if (!NT_STATUS_IS_OK(status)) {
1682 determine if the file size of a file can be changed,
1683 or if it is prevented by an already open file
1685 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1686 struct ntvfs_request *req,
1687 struct pvfs_filename *name,
1688 struct odb_lock **lckp)
1692 struct odb_lock *lck;
1693 uint32_t share_access;
1694 uint32_t access_mask;
1696 bool delete_on_close;
1698 status = pvfs_locking_key(name, name, &key);
1699 if (!NT_STATUS_IS_OK(status)) {
1700 return NT_STATUS_NO_MEMORY;
1703 lck = odb_lock(req, pvfs->odb_context, &key);
1705 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1706 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1709 share_access = NTCREATEX_SHARE_ACCESS_READ |
1710 NTCREATEX_SHARE_ACCESS_WRITE |
1711 NTCREATEX_SHARE_ACCESS_DELETE;
1713 * I would have thought that we would need to pass
1714 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1716 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1717 * to set the filesize.
1721 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1722 delete_on_close = false;
1723 break_to_none = true;
1725 status = odb_can_open(lck, name->stream_id,
1726 share_access, access_mask, delete_on_close,
1727 NTCREATEX_DISP_OPEN, break_to_none);
1730 * if it's a sharing violation or we got no oplock
1731 * only keep the lock if the caller requested access
1734 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1735 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1741 } else if (!NT_STATUS_IS_OK(status)) {
1754 determine if file meta data can be accessed, or if it is prevented by an
1757 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1758 struct ntvfs_request *req,
1759 struct pvfs_filename *name)
1763 struct odb_lock *lck;
1764 uint32_t share_access;
1765 uint32_t access_mask;
1766 bool delete_on_close;
1768 status = pvfs_locking_key(name, name, &key);
1769 if (!NT_STATUS_IS_OK(status)) {
1770 return NT_STATUS_NO_MEMORY;
1773 lck = odb_lock(req, pvfs->odb_context, &key);
1775 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1776 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1779 share_access = NTCREATEX_SHARE_ACCESS_READ |
1780 NTCREATEX_SHARE_ACCESS_WRITE;
1781 access_mask = SEC_FILE_READ_ATTRIBUTE;
1782 delete_on_close = false;
1784 status = odb_can_open(lck, name->stream_id,
1785 share_access, access_mask, delete_on_close,
1786 NTCREATEX_DISP_OPEN, false);
1788 if (!NT_STATUS_IS_OK(status)) {
1797 determine if delete on close is set on
1799 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1804 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1806 if (!NT_STATUS_IS_OK(status)) {
1807 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1811 return del_on_close;