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 /* if the client specified that it must not be a directory then
1121 check that it isn't */
1122 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1123 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1124 return NT_STATUS_FILE_IS_A_DIRECTORY;
1127 /* if the client specified that it must be a directory then
1129 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1130 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1131 return NT_STATUS_NOT_A_DIRECTORY;
1134 /* directory opens are handled separately */
1135 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1136 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1137 return pvfs_open_directory(pvfs, req, name, io);
1140 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1141 open doesn't match */
1142 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1144 create_options = io->generic.in.create_options;
1145 share_access = io->generic.in.share_access;
1146 access_mask = io->generic.in.access_mask;
1148 /* certain create options are not allowed */
1149 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1150 !(access_mask & SEC_STD_DELETE)) {
1151 return NT_STATUS_INVALID_PARAMETER;
1156 switch (io->generic.in.open_disposition) {
1157 case NTCREATEX_DISP_SUPERSEDE:
1158 case NTCREATEX_DISP_OVERWRITE_IF:
1159 if (name->stream_name == NULL) {
1162 stream_truncate = true;
1166 case NTCREATEX_DISP_OPEN:
1167 if (!name->stream_exists) {
1168 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1173 case NTCREATEX_DISP_OVERWRITE:
1174 if (!name->stream_exists) {
1175 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1177 if (name->stream_name == NULL) {
1180 stream_truncate = true;
1184 case NTCREATEX_DISP_CREATE:
1185 if (name->stream_exists) {
1186 return NT_STATUS_OBJECT_NAME_COLLISION;
1191 case NTCREATEX_DISP_OPEN_IF:
1196 return NT_STATUS_INVALID_PARAMETER;
1199 /* handle creating a new file separately */
1200 if (!name->exists) {
1201 status = pvfs_create_file(pvfs, req, name, io);
1202 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1206 /* we've hit a race - the file was created during this call */
1207 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1211 /* try re-resolving the name */
1212 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1213 if (!NT_STATUS_IS_OK(status)) {
1216 /* fall through to a normal open */
1219 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1220 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1221 return NT_STATUS_CANNOT_DELETE;
1224 /* check the security descriptor */
1225 status = pvfs_access_check(pvfs, req, name, &access_mask);
1226 if (!NT_STATUS_IS_OK(status)) {
1230 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1231 NT_STATUS_NOT_OK_RETURN(status);
1233 f = talloc(h, struct pvfs_file);
1235 return NT_STATUS_NO_MEMORY;
1238 f->handle = talloc(f, struct pvfs_file_handle);
1239 if (f->handle == NULL) {
1240 return NT_STATUS_NO_MEMORY;
1245 f->pending_list = NULL;
1247 f->share_access = io->generic.in.share_access;
1248 f->access_mask = access_mask;
1249 f->impersonation = io->generic.in.impersonation;
1250 f->notify_buffer = NULL;
1253 f->handle->pvfs = pvfs;
1255 f->handle->name = talloc_steal(f->handle, name);
1256 f->handle->create_options = io->generic.in.create_options;
1257 f->handle->seek_offset = 0;
1258 f->handle->position = 0;
1259 f->handle->mode = 0;
1260 f->handle->oplock = NULL;
1261 f->handle->have_opendb_entry = false;
1262 f->handle->open_completed = false;
1264 /* form the lock context used for byte range locking and
1266 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1267 if (!NT_STATUS_IS_OK(status)) {
1271 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1272 if (!NT_STATUS_IS_OK(status)) {
1276 /* get a lock on this file before the actual open */
1277 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1279 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1281 /* we were supposed to do a blocking lock, so something
1283 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1286 DLIST_ADD(pvfs->files.list, f);
1288 /* setup a destructor to avoid file descriptor leaks on
1289 abnormal termination */
1290 talloc_set_destructor(f, pvfs_fnum_destructor);
1291 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1294 * Only SMB2 takes care of the delete_on_close,
1297 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1298 req->ctx->protocol == PROTOCOL_SMB2) {
1299 del_on_close = true;
1301 del_on_close = false;
1304 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1305 oplock_level = OPLOCK_NONE;
1306 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1307 oplock_level = OPLOCK_BATCH;
1308 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1309 oplock_level = OPLOCK_EXCLUSIVE;
1312 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1313 allow_level_II_oplock = true;
1316 /* see if we are allowed to open at the same time as existing opens */
1317 status = odb_can_open(lck, name->stream_id,
1318 share_access, access_mask, del_on_close,
1319 io->generic.in.open_disposition, false);
1322 * on a sharing violation we need to retry when the file is closed by
1323 * the other user, or after 1 second
1324 * on a non granted oplock we need to retry when the file is closed by
1325 * the other user, or after 30 seconds
1327 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1328 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1329 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1330 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1333 if (!NT_STATUS_IS_OK(status)) {
1338 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1344 /* do the actual open */
1345 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1347 status = pvfs_map_errno(f->pvfs, errno);
1350 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1352 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1353 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1354 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1363 /* now really mark the file as open */
1364 status = odb_open_file(lck, f->handle, name->full_name,
1365 &f->handle->fd, allow_level_II_oplock,
1366 oplock_level, &oplock_granted);
1368 if (!NT_STATUS_IS_OK(status)) {
1373 f->handle->have_opendb_entry = true;
1375 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1376 oplock_granted = OPLOCK_BATCH;
1377 } else if (oplock_granted != OPLOCK_NONE) {
1378 status = pvfs_setup_oplock(f, oplock_granted);
1379 if (!NT_STATUS_IS_OK(status)) {
1385 stream_existed = name->stream_exists;
1387 /* if this was a stream create then create the stream as well */
1388 if (!name->stream_exists) {
1389 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1390 if (!NT_STATUS_IS_OK(status)) {
1394 if (stream_truncate) {
1395 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1396 if (!NT_STATUS_IS_OK(status)) {
1403 /* re-resolve the open fd */
1404 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1405 if (!NT_STATUS_IS_OK(status)) {
1410 if (f->handle->name->stream_id == 0 &&
1411 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1412 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1413 /* for overwrite we need to replace file permissions */
1414 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1415 mode_t mode = pvfs_fileperms(pvfs, attrib);
1416 if (fchmod(fd, mode) == -1) {
1418 return pvfs_map_errno(pvfs, errno);
1420 name->dos.attrib = attrib;
1421 status = pvfs_dosattrib_save(pvfs, name, fd);
1422 if (!NT_STATUS_IS_OK(status)) {
1430 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1431 NT_STATUS_NOT_OK_RETURN(status);
1433 /* mark the open as having completed fully, so delete on close
1435 f->handle->open_completed = true;
1437 io->generic.out.oplock_level = oplock_granted;
1438 io->generic.out.file.ntvfs = h;
1439 io->generic.out.create_action = stream_existed?
1440 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1441 io->generic.out.create_time = name->dos.create_time;
1442 io->generic.out.access_time = name->dos.access_time;
1443 io->generic.out.write_time = name->dos.write_time;
1444 io->generic.out.change_time = name->dos.change_time;
1445 io->generic.out.attrib = name->dos.attrib;
1446 io->generic.out.alloc_size = name->dos.alloc_size;
1447 io->generic.out.size = name->st.st_size;
1448 io->generic.out.file_type = FILE_TYPE_DISK;
1449 io->generic.out.ipc_state = 0;
1450 io->generic.out.is_directory = 0;
1452 return NT_STATUS_OK;
1459 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1460 struct ntvfs_request *req, union smb_close *io)
1462 struct pvfs_state *pvfs = ntvfs->private_data;
1463 struct pvfs_file *f;
1464 struct utimbuf unix_times;
1466 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1467 return NT_STATUS_DOS(ERRSRV, ERRerror);
1470 if (io->generic.level != RAW_CLOSE_CLOSE) {
1471 return ntvfs_map_close(ntvfs, req, io);
1474 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1476 return NT_STATUS_INVALID_HANDLE;
1479 if (!null_time(io->close.in.write_time)) {
1480 unix_times.actime = 0;
1481 unix_times.modtime = io->close.in.write_time;
1482 utime(f->handle->name->full_name, &unix_times);
1487 return NT_STATUS_OK;
1492 logoff - close all file descriptors open by a vuid
1494 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1495 struct ntvfs_request *req)
1497 struct pvfs_state *pvfs = ntvfs->private_data;
1498 struct pvfs_file *f, *next;
1500 for (f=pvfs->files.list;f;f=next) {
1502 if (f->ntvfs->session_info == req->session_info) {
1507 return NT_STATUS_OK;
1512 exit - close files for the current pid
1514 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1515 struct ntvfs_request *req)
1517 struct pvfs_state *pvfs = ntvfs->private_data;
1518 struct pvfs_file *f, *next;
1520 for (f=pvfs->files.list;f;f=next) {
1522 if (f->ntvfs->session_info == req->session_info &&
1523 f->ntvfs->smbpid == req->smbpid) {
1528 return NT_STATUS_OK;
1533 change the delete on close flag on an already open file
1535 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1536 struct ntvfs_request *req,
1537 struct pvfs_file *f, bool del_on_close)
1539 struct odb_lock *lck;
1542 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1543 return NT_STATUS_CANNOT_DELETE;
1546 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1547 !pvfs_directory_empty(pvfs, f->handle->name)) {
1548 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1552 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1554 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1557 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1559 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1562 status = odb_set_delete_on_close(lck, del_on_close);
1571 determine if a file can be deleted, or if it is prevented by an
1574 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1575 struct ntvfs_request *req,
1576 struct pvfs_filename *name,
1577 struct odb_lock **lckp)
1581 struct odb_lock *lck;
1582 uint32_t share_access;
1583 uint32_t access_mask;
1584 bool delete_on_close;
1586 status = pvfs_locking_key(name, name, &key);
1587 if (!NT_STATUS_IS_OK(status)) {
1588 return NT_STATUS_NO_MEMORY;
1591 lck = odb_lock(req, pvfs->odb_context, &key);
1593 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1594 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1597 share_access = NTCREATEX_SHARE_ACCESS_READ |
1598 NTCREATEX_SHARE_ACCESS_WRITE |
1599 NTCREATEX_SHARE_ACCESS_DELETE;
1600 access_mask = SEC_STD_DELETE;
1601 delete_on_close = true;
1603 status = odb_can_open(lck, name->stream_id,
1604 share_access, access_mask, delete_on_close,
1605 NTCREATEX_DISP_OPEN, false);
1607 if (NT_STATUS_IS_OK(status)) {
1608 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1612 * if it's a sharing violation or we got no oplock
1613 * only keep the lock if the caller requested access
1616 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1617 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1623 } else if (!NT_STATUS_IS_OK(status)) {
1636 determine if a file can be renamed, or if it is prevented by an
1639 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1640 struct ntvfs_request *req,
1641 struct pvfs_filename *name,
1642 struct odb_lock **lckp)
1646 struct odb_lock *lck;
1647 uint32_t share_access;
1648 uint32_t access_mask;
1649 bool delete_on_close;
1651 status = pvfs_locking_key(name, name, &key);
1652 if (!NT_STATUS_IS_OK(status)) {
1653 return NT_STATUS_NO_MEMORY;
1656 lck = odb_lock(req, pvfs->odb_context, &key);
1658 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1659 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1662 share_access = NTCREATEX_SHARE_ACCESS_READ |
1663 NTCREATEX_SHARE_ACCESS_WRITE;
1664 access_mask = SEC_STD_DELETE;
1665 delete_on_close = false;
1667 status = odb_can_open(lck, name->stream_id,
1668 share_access, access_mask, delete_on_close,
1669 NTCREATEX_DISP_OPEN, false);
1672 * if it's a sharing violation or we got no oplock
1673 * only keep the lock if the caller requested access
1676 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1677 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1683 } else if (!NT_STATUS_IS_OK(status)) {
1696 determine if the file size of a file can be changed,
1697 or if it is prevented by an already open file
1699 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1700 struct ntvfs_request *req,
1701 struct pvfs_filename *name,
1702 struct odb_lock **lckp)
1706 struct odb_lock *lck;
1707 uint32_t share_access;
1708 uint32_t access_mask;
1710 bool delete_on_close;
1712 status = pvfs_locking_key(name, name, &key);
1713 if (!NT_STATUS_IS_OK(status)) {
1714 return NT_STATUS_NO_MEMORY;
1717 lck = odb_lock(req, pvfs->odb_context, &key);
1719 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1720 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1723 share_access = NTCREATEX_SHARE_ACCESS_READ |
1724 NTCREATEX_SHARE_ACCESS_WRITE |
1725 NTCREATEX_SHARE_ACCESS_DELETE;
1727 * I would have thought that we would need to pass
1728 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1730 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1731 * to set the filesize.
1735 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1736 delete_on_close = false;
1737 break_to_none = true;
1739 status = odb_can_open(lck, name->stream_id,
1740 share_access, access_mask, delete_on_close,
1741 NTCREATEX_DISP_OPEN, break_to_none);
1744 * if it's a sharing violation or we got no oplock
1745 * only keep the lock if the caller requested access
1748 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1749 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1755 } else if (!NT_STATUS_IS_OK(status)) {
1768 determine if file meta data can be accessed, or if it is prevented by an
1771 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1772 struct ntvfs_request *req,
1773 struct pvfs_filename *name)
1777 struct odb_lock *lck;
1778 uint32_t share_access;
1779 uint32_t access_mask;
1780 bool delete_on_close;
1782 status = pvfs_locking_key(name, name, &key);
1783 if (!NT_STATUS_IS_OK(status)) {
1784 return NT_STATUS_NO_MEMORY;
1787 lck = odb_lock(req, pvfs->odb_context, &key);
1789 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1790 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1793 share_access = NTCREATEX_SHARE_ACCESS_READ |
1794 NTCREATEX_SHARE_ACCESS_WRITE;
1795 access_mask = SEC_FILE_READ_ATTRIBUTE;
1796 delete_on_close = false;
1798 status = odb_can_open(lck, name->stream_id,
1799 share_access, access_mask, delete_on_close,
1800 NTCREATEX_DISP_OPEN, false);
1802 if (!NT_STATUS_IS_OK(status)) {
1811 determine if delete on close is set on
1813 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1818 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1820 if (!NT_STATUS_IS_OK(status)) {
1821 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1825 return del_on_close;