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->sticky_write_time = false;
266 f->handle->open_completed = false;
268 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
269 pvfs_directory_empty(pvfs, f->handle->name)) {
272 del_on_close = false;
276 /* form the lock context used for opendb locking */
277 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
278 if (!NT_STATUS_IS_OK(status)) {
282 /* get a lock on this file before the actual open */
283 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
285 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
287 /* we were supposed to do a blocking lock, so something
289 return NT_STATUS_INTERNAL_DB_CORRUPTION;
292 /* see if we are allowed to open at the same time as existing opens */
293 status = odb_can_open(lck, name->stream_id,
294 share_access, access_mask, del_on_close,
295 io->generic.in.open_disposition, false);
296 if (!NT_STATUS_IS_OK(status)) {
301 /* now really mark the file as open */
302 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
303 share_access, access_mask, del_on_close,
304 io->generic.in.open_disposition,
305 false, false, OPLOCK_NONE, NULL);
307 if (!NT_STATUS_IS_OK(status)) {
312 f->handle->have_opendb_entry = true;
315 DLIST_ADD(pvfs->files.list, f);
317 /* setup destructors to avoid leaks on abnormal termination */
318 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
319 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
322 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
323 mode_t mode = pvfs_fileperms(pvfs, attrib);
325 if (mkdir(name->full_name, mode) == -1) {
326 return pvfs_map_errno(pvfs,errno);
329 pvfs_xattr_unlink_hook(pvfs, name->full_name);
331 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
332 if (!NT_STATUS_IS_OK(status)) {
336 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
337 if (!NT_STATUS_IS_OK(status)) {
341 /* form the lock context used for opendb locking */
342 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
343 if (!NT_STATUS_IS_OK(status)) {
347 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
349 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
351 /* we were supposed to do a blocking lock, so something
353 return NT_STATUS_INTERNAL_DB_CORRUPTION;
356 status = odb_can_open(lck, name->stream_id,
357 share_access, access_mask, del_on_close,
358 io->generic.in.open_disposition, false);
360 if (!NT_STATUS_IS_OK(status)) {
364 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
365 share_access, access_mask, del_on_close,
366 io->generic.in.open_disposition,
367 false, false, OPLOCK_NONE, NULL);
369 if (!NT_STATUS_IS_OK(status)) {
373 f->handle->have_opendb_entry = true;
375 create_action = NTCREATEX_ACTION_CREATED;
377 notify_trigger(pvfs->notify_context,
379 FILE_NOTIFY_CHANGE_DIR_NAME,
382 create_action = NTCREATEX_ACTION_EXISTED;
386 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
389 /* the open succeeded, keep this handle permanently */
390 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
391 if (!NT_STATUS_IS_OK(status)) {
395 f->handle->open_completed = true;
397 io->generic.out.oplock_level = OPLOCK_NONE;
398 io->generic.out.file.ntvfs = h;
399 io->generic.out.create_action = create_action;
400 io->generic.out.create_time = name->dos.create_time;
401 io->generic.out.access_time = name->dos.access_time;
402 io->generic.out.write_time = name->dos.write_time;
403 io->generic.out.change_time = name->dos.change_time;
404 io->generic.out.attrib = name->dos.attrib;
405 io->generic.out.alloc_size = name->dos.alloc_size;
406 io->generic.out.size = name->st.st_size;
407 io->generic.out.file_type = FILE_TYPE_DISK;
408 io->generic.out.ipc_state = 0;
409 io->generic.out.is_directory = 1;
414 rmdir(name->full_name);
419 destroy a struct pvfs_file_handle
421 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
423 /* the write time is no longer sticky */
424 if (h->sticky_write_time) {
426 status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
427 if (NT_STATUS_IS_OK(status)) {
428 h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
429 pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
433 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
434 h->name->stream_name) {
436 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
437 if (!NT_STATUS_IS_OK(status)) {
438 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
439 h->name->stream_name, h->name->full_name));
444 if (close(h->fd) != 0) {
445 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
446 h->fd, h->name->full_name, strerror(errno)));
451 if (h->have_opendb_entry) {
452 struct odb_lock *lck;
454 const char *delete_path = NULL;
456 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
458 DEBUG(0,("Unable to lock opendb for close\n"));
462 status = odb_close_file(lck, h, &delete_path);
463 if (!NT_STATUS_IS_OK(status)) {
464 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
465 h->name->full_name, nt_errstr(status)));
468 if (h->name->stream_name == NULL &&
469 h->open_completed && delete_path) {
470 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
471 if (!NT_STATUS_IS_OK(status)) {
472 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
473 delete_path, nt_errstr(status)));
475 if (unlink(delete_path) != 0) {
476 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
477 delete_path, strerror(errno)));
479 notify_trigger(h->pvfs->notify_context,
480 NOTIFY_ACTION_REMOVED,
481 FILE_NOTIFY_CHANGE_FILE_NAME,
494 destroy a struct pvfs_file
496 static int pvfs_fnum_destructor(struct pvfs_file *f)
498 DLIST_REMOVE(f->pvfs->files.list, f);
499 pvfs_lock_close(f->pvfs, f);
500 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
507 form the lock context used for byte range locking. This is separate
508 from the locking key used for opendb locking as it needs to take
509 account of file streams (each stream is a separate byte range
512 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
513 struct pvfs_filename *name,
514 struct ntvfs_handle *ntvfs,
515 struct brl_handle **_h)
517 DATA_BLOB odb_key, key;
519 struct brl_handle *h;
521 status = pvfs_locking_key(name, mem_ctx, &odb_key);
522 NT_STATUS_NOT_OK_RETURN(status);
524 if (name->stream_name == NULL) {
527 key = data_blob_talloc(mem_ctx, NULL,
528 odb_key.length + strlen(name->stream_name) + 1);
529 NT_STATUS_HAVE_NO_MEMORY(key.data);
530 memcpy(key.data, odb_key.data, odb_key.length);
531 memcpy(key.data + odb_key.length,
532 name->stream_name, strlen(name->stream_name) + 1);
533 data_blob_free(&odb_key);
536 h = brl_create_handle(mem_ctx, ntvfs, &key);
537 NT_STATUS_HAVE_NO_MEMORY(h);
546 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
547 struct ntvfs_request *req,
548 struct pvfs_filename *name,
553 struct ntvfs_handle *h;
555 struct odb_lock *lck;
556 uint32_t create_options = io->generic.in.create_options;
557 uint32_t share_access = io->generic.in.share_access;
558 uint32_t access_mask = io->generic.in.access_mask;
562 struct pvfs_filename *parent;
563 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
564 bool allow_level_II_oplock = false;
566 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
567 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
568 return NT_STATUS_CANNOT_DELETE;
571 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
572 NT_STATUS_NOT_OK_RETURN(status);
574 /* check that the parent isn't opened with delete on close set */
575 status = pvfs_resolve_parent(pvfs, req, name, &parent);
576 if (NT_STATUS_IS_OK(status)) {
577 DATA_BLOB locking_key;
578 status = pvfs_locking_key(parent, req, &locking_key);
579 NT_STATUS_NOT_OK_RETURN(status);
580 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key,
582 NT_STATUS_NOT_OK_RETURN(status);
584 return NT_STATUS_DELETE_PENDING;
588 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
594 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
595 NT_STATUS_NOT_OK_RETURN(status);
597 f = talloc(h, struct pvfs_file);
598 NT_STATUS_HAVE_NO_MEMORY(f);
600 f->handle = talloc(f, struct pvfs_file_handle);
601 NT_STATUS_HAVE_NO_MEMORY(f->handle);
603 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
604 mode = pvfs_fileperms(pvfs, attrib);
606 /* create the file */
607 fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
609 return pvfs_map_errno(pvfs, errno);
612 pvfs_xattr_unlink_hook(pvfs, name->full_name);
614 /* if this was a stream create then create the stream as well */
615 if (name->stream_name) {
616 status = pvfs_stream_create(pvfs, name, fd);
617 if (!NT_STATUS_IS_OK(status)) {
623 /* re-resolve the open fd */
624 status = pvfs_resolve_name_fd(pvfs, fd, name);
625 if (!NT_STATUS_IS_OK(status)) {
630 name->dos.attrib = attrib;
631 status = pvfs_dosattrib_save(pvfs, name, fd);
632 if (!NT_STATUS_IS_OK(status)) {
637 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
638 if (!NT_STATUS_IS_OK(status)) {
642 /* form the lock context used for byte range locking and
644 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
645 if (!NT_STATUS_IS_OK(status)) {
649 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
650 if (!NT_STATUS_IS_OK(status)) {
654 /* grab a lock on the open file record */
655 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
657 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
659 /* we were supposed to do a blocking lock, so something
661 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
665 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
668 del_on_close = false;
671 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
672 oplock_level = OPLOCK_NONE;
673 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
674 oplock_level = OPLOCK_BATCH;
675 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
676 oplock_level = OPLOCK_EXCLUSIVE;
679 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
680 allow_level_II_oplock = true;
683 status = odb_can_open(lck, name->stream_id,
684 share_access, access_mask, del_on_close,
685 io->generic.in.open_disposition, false);
686 if (!NT_STATUS_IS_OK(status)) {
688 /* bad news, we must have hit a race - we don't delete the file
689 here as the most likely scenario is that someone else created
690 the file at the same time */
695 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
696 share_access, access_mask, del_on_close,
697 io->generic.in.open_disposition,
698 false, allow_level_II_oplock,
699 oplock_level, &oplock_granted);
701 if (!NT_STATUS_IS_OK(status)) {
702 /* bad news, we must have hit a race - we don't delete the file
703 here as the most likely scenario is that someone else created
704 the file at the same time */
712 f->pending_list = NULL;
714 f->share_access = io->generic.in.share_access;
715 f->access_mask = access_mask;
716 f->impersonation = io->generic.in.impersonation;
717 f->notify_buffer = NULL;
720 f->handle->pvfs = pvfs;
721 f->handle->name = talloc_steal(f->handle, name);
723 f->handle->create_options = io->generic.in.create_options;
724 f->handle->seek_offset = 0;
725 f->handle->position = 0;
727 f->handle->oplock = NULL;
728 f->handle->have_opendb_entry = true;
729 f->handle->sticky_write_time = false;
730 f->handle->open_completed = false;
732 DLIST_ADD(pvfs->files.list, f);
734 /* setup a destructor to avoid file descriptor leaks on
735 abnormal termination */
736 talloc_set_destructor(f, pvfs_fnum_destructor);
737 talloc_set_destructor(f->handle, pvfs_handle_destructor);
739 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
740 oplock_granted = OPLOCK_BATCH;
741 } else if (oplock_granted != OPLOCK_NONE) {
742 status = pvfs_setup_oplock(f, oplock_granted);
743 if (!NT_STATUS_IS_OK(status)) {
748 io->generic.out.oplock_level = oplock_granted;
749 io->generic.out.file.ntvfs = f->ntvfs;
750 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
751 io->generic.out.create_time = name->dos.create_time;
752 io->generic.out.access_time = name->dos.access_time;
753 io->generic.out.write_time = name->dos.write_time;
754 io->generic.out.change_time = name->dos.change_time;
755 io->generic.out.attrib = name->dos.attrib;
756 io->generic.out.alloc_size = name->dos.alloc_size;
757 io->generic.out.size = name->st.st_size;
758 io->generic.out.file_type = FILE_TYPE_DISK;
759 io->generic.out.ipc_state = 0;
760 io->generic.out.is_directory = 0;
762 /* success - keep the file handle */
763 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
764 if (!NT_STATUS_IS_OK(status)) {
768 f->handle->open_completed = true;
770 notify_trigger(pvfs->notify_context,
772 FILE_NOTIFY_CHANGE_FILE_NAME,
779 unlink(name->full_name);
784 state of a pending retry
786 struct pvfs_odb_retry {
787 struct ntvfs_module_context *ntvfs;
788 struct ntvfs_request *req;
789 DATA_BLOB odb_locking_key;
792 void (*callback)(struct pvfs_odb_retry *r,
793 struct ntvfs_module_context *ntvfs,
794 struct ntvfs_request *req,
797 enum pvfs_wait_notice reason);
800 /* destroy a pending request */
801 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
803 struct pvfs_state *pvfs = r->ntvfs->private_data;
804 if (r->odb_locking_key.data) {
805 struct odb_lock *lck;
806 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
808 odb_remove_pending(lck, r);
815 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
817 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
819 if (reason == PVFS_WAIT_EVENT) {
821 * The pending odb entry is already removed.
822 * We use a null locking key to indicate this
825 data_blob_free(&r->odb_locking_key);
828 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
832 setup for a retry of a request that was rejected
835 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
836 struct ntvfs_request *req,
837 struct odb_lock *lck,
838 struct timeval end_time,
841 void (*callback)(struct pvfs_odb_retry *r,
842 struct ntvfs_module_context *ntvfs,
843 struct ntvfs_request *req,
846 enum pvfs_wait_notice reason))
848 struct pvfs_state *pvfs = ntvfs->private_data;
849 struct pvfs_odb_retry *r;
850 struct pvfs_wait *wait_handle;
853 r = talloc(req, struct pvfs_odb_retry);
854 NT_STATUS_HAVE_NO_MEMORY(r);
859 r->private_data = private_data;
860 r->callback = callback;
861 r->odb_locking_key = odb_get_key(r, lck);
862 if (r->odb_locking_key.data == NULL) {
863 return NT_STATUS_NO_MEMORY;
866 /* setup a pending lock */
867 status = odb_open_file_pending(lck, r);
868 if (!NT_STATUS_IS_OK(status)) {
874 talloc_set_destructor(r, pvfs_odb_retry_destructor);
876 wait_handle = pvfs_wait_message(pvfs, req,
877 MSG_PVFS_RETRY_OPEN, end_time,
878 pvfs_odb_retry_callback, r);
879 if (wait_handle == NULL) {
880 return NT_STATUS_NO_MEMORY;
883 talloc_steal(r, wait_handle);
885 talloc_steal(pvfs, r);
891 retry an open after a sharing violation
893 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
894 struct ntvfs_module_context *ntvfs,
895 struct ntvfs_request *req,
898 enum pvfs_wait_notice reason)
900 union smb_open *io = talloc_get_type(_io, union smb_open);
903 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
904 just a bug in their server, but we better do the same */
905 if (reason == PVFS_WAIT_CANCEL) {
909 if (reason == PVFS_WAIT_TIMEOUT) {
910 /* if it timed out, then give the failure
913 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
914 req->async_states->send_fn(req);
920 /* try the open again, which could trigger another retry setup
921 if it wants to, so we have to unmark the async flag so we
922 will know if it does a second async reply */
923 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
925 status = pvfs_open(ntvfs, req, io);
926 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
927 /* the 2nd try also replied async, so we don't send
932 /* re-mark it async, just in case someone up the chain does
934 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
936 /* send the reply up the chain */
937 req->async_states->status = status;
938 req->async_states->send_fn(req);
943 special handling for openx DENY_DOS semantics
945 This function attempts a reference open using an existing handle. If its allowed,
946 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
947 open processing continues.
949 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
950 struct ntvfs_request *req, union smb_open *io,
951 struct pvfs_file *f, struct odb_lock *lck)
953 struct pvfs_state *pvfs = ntvfs->private_data;
954 struct pvfs_file *f2;
955 struct pvfs_filename *name;
958 /* search for an existing open with the right parameters. Note
959 the magic ntcreatex options flag, which is set in the
960 generic mapping code. This might look ugly, but its
961 actually pretty much now w2k does it internally as well.
963 If you look at the BASE-DENYDOS test you will see that a
964 DENY_DOS is a very special case, and in the right
965 circumstances you actually get the _same_ handle back
966 twice, rather than a new handle.
968 for (f2=pvfs->files.list;f2;f2=f2->next) {
970 f2->ntvfs->session_info == req->session_info &&
971 f2->ntvfs->smbpid == req->smbpid &&
972 (f2->handle->create_options &
973 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
974 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
975 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
976 strcasecmp_m(f2->handle->name->original_name,
977 io->generic.in.fname)==0) {
983 return NT_STATUS_SHARING_VIOLATION;
986 /* quite an insane set of semantics ... */
987 if (is_exe_filename(io->generic.in.fname) &&
988 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
989 return NT_STATUS_SHARING_VIOLATION;
993 setup a reference to the existing handle
995 talloc_free(f->handle);
996 f->handle = talloc_reference(f, f2->handle);
1000 name = f->handle->name;
1002 io->generic.out.oplock_level = OPLOCK_NONE;
1003 io->generic.out.file.ntvfs = f->ntvfs;
1004 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1005 io->generic.out.create_time = name->dos.create_time;
1006 io->generic.out.access_time = name->dos.access_time;
1007 io->generic.out.write_time = name->dos.write_time;
1008 io->generic.out.change_time = name->dos.change_time;
1009 io->generic.out.attrib = name->dos.attrib;
1010 io->generic.out.alloc_size = name->dos.alloc_size;
1011 io->generic.out.size = name->st.st_size;
1012 io->generic.out.file_type = FILE_TYPE_DISK;
1013 io->generic.out.ipc_state = 0;
1014 io->generic.out.is_directory = 0;
1016 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1017 NT_STATUS_NOT_OK_RETURN(status);
1019 return NT_STATUS_OK;
1025 setup for a open retry after a sharing violation
1027 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1028 struct ntvfs_request *req,
1030 struct pvfs_file *f,
1031 struct odb_lock *lck,
1032 NTSTATUS parent_status)
1034 struct pvfs_state *pvfs = ntvfs->private_data;
1036 struct timeval end_time;
1038 if (io->generic.in.create_options &
1039 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1040 /* see if we can satisfy the request using the special DENY_DOS
1042 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1043 if (NT_STATUS_IS_OK(status)) {
1048 /* the retry should allocate a new file handle */
1051 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1052 end_time = timeval_add(&req->statistics.request_time,
1053 0, pvfs->sharing_violation_delay);
1054 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1055 end_time = timeval_add(&req->statistics.request_time,
1056 pvfs->oplock_break_timeout, 0);
1058 return NT_STATUS_INTERNAL_ERROR;
1061 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
1062 pvfs_retry_open_sharing);
1068 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1069 struct ntvfs_request *req, union smb_open *io)
1071 struct pvfs_state *pvfs = ntvfs->private_data;
1073 struct pvfs_filename *name;
1074 struct pvfs_file *f;
1075 struct ntvfs_handle *h;
1078 struct odb_lock *lck;
1079 uint32_t create_options;
1080 uint32_t share_access;
1081 uint32_t access_mask;
1083 bool stream_existed, stream_truncate=false;
1084 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1085 bool allow_level_II_oplock = false;
1087 /* use the generic mapping code to avoid implementing all the
1088 different open calls. */
1089 if (io->generic.level != RAW_OPEN_GENERIC &&
1090 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1091 return ntvfs_map_open(ntvfs, req, io);
1094 /* resolve the cifs name to a posix name */
1095 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1096 PVFS_RESOLVE_STREAMS, &name);
1097 if (!NT_STATUS_IS_OK(status)) {
1101 /* directory opens are handled separately */
1102 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1103 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1104 return pvfs_open_directory(pvfs, req, name, io);
1107 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1108 open doesn't match */
1109 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1111 create_options = io->generic.in.create_options;
1112 share_access = io->generic.in.share_access;
1113 access_mask = io->generic.in.access_mask;
1115 /* certain create options are not allowed */
1116 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1117 !(access_mask & SEC_STD_DELETE)) {
1118 return NT_STATUS_INVALID_PARAMETER;
1123 switch (io->generic.in.open_disposition) {
1124 case NTCREATEX_DISP_SUPERSEDE:
1125 case NTCREATEX_DISP_OVERWRITE_IF:
1126 if (name->stream_name == NULL) {
1129 stream_truncate = true;
1133 case NTCREATEX_DISP_OPEN:
1134 if (!name->stream_exists) {
1135 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1140 case NTCREATEX_DISP_OVERWRITE:
1141 if (!name->stream_exists) {
1142 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1144 if (name->stream_name == NULL) {
1147 stream_truncate = true;
1151 case NTCREATEX_DISP_CREATE:
1152 if (name->stream_exists) {
1153 return NT_STATUS_OBJECT_NAME_COLLISION;
1158 case NTCREATEX_DISP_OPEN_IF:
1163 return NT_STATUS_INVALID_PARAMETER;
1166 /* handle creating a new file separately */
1167 if (!name->exists) {
1168 status = pvfs_create_file(pvfs, req, name, io);
1169 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1173 /* we've hit a race - the file was created during this call */
1174 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1178 /* try re-resolving the name */
1179 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1180 if (!NT_STATUS_IS_OK(status)) {
1183 /* fall through to a normal open */
1186 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1187 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1188 return NT_STATUS_CANNOT_DELETE;
1191 /* check the security descriptor */
1192 status = pvfs_access_check(pvfs, req, name, &access_mask);
1193 if (!NT_STATUS_IS_OK(status)) {
1197 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1198 NT_STATUS_NOT_OK_RETURN(status);
1200 f = talloc(h, struct pvfs_file);
1202 return NT_STATUS_NO_MEMORY;
1205 f->handle = talloc(f, struct pvfs_file_handle);
1206 if (f->handle == NULL) {
1207 return NT_STATUS_NO_MEMORY;
1212 f->pending_list = NULL;
1214 f->share_access = io->generic.in.share_access;
1215 f->access_mask = access_mask;
1216 f->impersonation = io->generic.in.impersonation;
1217 f->notify_buffer = NULL;
1220 f->handle->pvfs = pvfs;
1222 f->handle->name = talloc_steal(f->handle, name);
1223 f->handle->create_options = io->generic.in.create_options;
1224 f->handle->seek_offset = 0;
1225 f->handle->position = 0;
1226 f->handle->mode = 0;
1227 f->handle->oplock = NULL;
1228 f->handle->have_opendb_entry = false;
1229 f->handle->sticky_write_time = false;
1230 f->handle->open_completed = false;
1232 /* form the lock context used for byte range locking and
1234 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1235 if (!NT_STATUS_IS_OK(status)) {
1239 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1240 if (!NT_STATUS_IS_OK(status)) {
1244 /* get a lock on this file before the actual open */
1245 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1247 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1249 /* we were supposed to do a blocking lock, so something
1251 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1254 DLIST_ADD(pvfs->files.list, f);
1256 /* setup a destructor to avoid file descriptor leaks on
1257 abnormal termination */
1258 talloc_set_destructor(f, pvfs_fnum_destructor);
1259 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1262 * Only SMB2 takes care of the delete_on_close,
1265 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1266 req->ctx->protocol == PROTOCOL_SMB2) {
1267 del_on_close = true;
1269 del_on_close = false;
1272 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1273 oplock_level = OPLOCK_NONE;
1274 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1275 oplock_level = OPLOCK_BATCH;
1276 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1277 oplock_level = OPLOCK_EXCLUSIVE;
1280 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1281 allow_level_II_oplock = true;
1284 /* see if we are allowed to open at the same time as existing opens */
1285 status = odb_can_open(lck, name->stream_id,
1286 share_access, access_mask, del_on_close,
1287 io->generic.in.open_disposition, false);
1290 * on a sharing violation we need to retry when the file is closed by
1291 * the other user, or after 1 second
1292 * on a non granted oplock we need to retry when the file is closed by
1293 * the other user, or after 30 seconds
1295 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1296 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1297 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1298 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1301 if (!NT_STATUS_IS_OK(status)) {
1306 /* now really mark the file as open */
1307 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
1308 share_access, access_mask, del_on_close,
1309 io->generic.in.open_disposition,
1310 false, allow_level_II_oplock,
1311 oplock_level, &oplock_granted);
1313 if (!NT_STATUS_IS_OK(status)) {
1318 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1319 oplock_granted = OPLOCK_BATCH;
1320 } else if (oplock_granted != OPLOCK_NONE) {
1321 status = pvfs_setup_oplock(f, oplock_granted);
1322 if (!NT_STATUS_IS_OK(status)) {
1328 f->handle->have_opendb_entry = true;
1330 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1336 /* do the actual open */
1337 fd = open(f->handle->name->full_name, flags);
1340 return pvfs_map_errno(f->pvfs, errno);
1345 stream_existed = name->stream_exists;
1347 /* if this was a stream create then create the stream as well */
1348 if (!name->stream_exists) {
1349 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1350 if (!NT_STATUS_IS_OK(status)) {
1354 if (stream_truncate) {
1355 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1356 if (!NT_STATUS_IS_OK(status)) {
1363 /* re-resolve the open fd */
1364 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1365 if (!NT_STATUS_IS_OK(status)) {
1370 if (f->handle->name->stream_id == 0 &&
1371 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1372 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1373 /* for overwrite we need to replace file permissions */
1374 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1375 mode_t mode = pvfs_fileperms(pvfs, attrib);
1376 if (fchmod(fd, mode) == -1) {
1378 return pvfs_map_errno(pvfs, errno);
1380 name->dos.attrib = attrib;
1381 status = pvfs_dosattrib_save(pvfs, name, fd);
1382 if (!NT_STATUS_IS_OK(status)) {
1390 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1391 NT_STATUS_NOT_OK_RETURN(status);
1393 /* mark the open as having completed fully, so delete on close
1395 f->handle->open_completed = true;
1397 io->generic.out.oplock_level = oplock_granted;
1398 io->generic.out.file.ntvfs = h;
1399 io->generic.out.create_action = stream_existed?
1400 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1401 io->generic.out.create_time = name->dos.create_time;
1402 io->generic.out.access_time = name->dos.access_time;
1403 io->generic.out.write_time = name->dos.write_time;
1404 io->generic.out.change_time = name->dos.change_time;
1405 io->generic.out.attrib = name->dos.attrib;
1406 io->generic.out.alloc_size = name->dos.alloc_size;
1407 io->generic.out.size = name->st.st_size;
1408 io->generic.out.file_type = FILE_TYPE_DISK;
1409 io->generic.out.ipc_state = 0;
1410 io->generic.out.is_directory = 0;
1412 return NT_STATUS_OK;
1419 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1420 struct ntvfs_request *req, union smb_close *io)
1422 struct pvfs_state *pvfs = ntvfs->private_data;
1423 struct pvfs_file *f;
1424 struct utimbuf unix_times;
1426 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1427 return NT_STATUS_DOS(ERRSRV, ERRerror);
1430 if (io->generic.level != RAW_CLOSE_CLOSE) {
1431 return ntvfs_map_close(ntvfs, req, io);
1434 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1436 return NT_STATUS_INVALID_HANDLE;
1439 if (!null_time(io->close.in.write_time)) {
1440 unix_times.actime = 0;
1441 unix_times.modtime = io->close.in.write_time;
1442 utime(f->handle->name->full_name, &unix_times);
1443 } else if (f->handle->sticky_write_time) {
1444 unix_times.actime = 0;
1445 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1446 utime(f->handle->name->full_name, &unix_times);
1451 return NT_STATUS_OK;
1456 logoff - close all file descriptors open by a vuid
1458 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1459 struct ntvfs_request *req)
1461 struct pvfs_state *pvfs = ntvfs->private_data;
1462 struct pvfs_file *f, *next;
1464 for (f=pvfs->files.list;f;f=next) {
1466 if (f->ntvfs->session_info == req->session_info) {
1471 return NT_STATUS_OK;
1476 exit - close files for the current pid
1478 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1479 struct ntvfs_request *req)
1481 struct pvfs_state *pvfs = ntvfs->private_data;
1482 struct pvfs_file *f, *next;
1484 for (f=pvfs->files.list;f;f=next) {
1486 if (f->ntvfs->session_info == req->session_info &&
1487 f->ntvfs->smbpid == req->smbpid) {
1492 return NT_STATUS_OK;
1497 change the delete on close flag on an already open file
1499 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1500 struct ntvfs_request *req,
1501 struct pvfs_file *f, bool del_on_close)
1503 struct odb_lock *lck;
1506 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1507 return NT_STATUS_CANNOT_DELETE;
1510 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1511 !pvfs_directory_empty(pvfs, f->handle->name)) {
1512 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1516 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1518 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1521 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1523 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1526 status = odb_set_delete_on_close(lck, del_on_close);
1535 determine if a file can be deleted, or if it is prevented by an
1538 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1539 struct ntvfs_request *req,
1540 struct pvfs_filename *name,
1541 struct odb_lock **lckp)
1545 struct odb_lock *lck;
1546 uint32_t share_access;
1547 uint32_t access_mask;
1548 bool delete_on_close;
1550 status = pvfs_locking_key(name, name, &key);
1551 if (!NT_STATUS_IS_OK(status)) {
1552 return NT_STATUS_NO_MEMORY;
1555 lck = odb_lock(req, pvfs->odb_context, &key);
1557 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1558 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1561 share_access = NTCREATEX_SHARE_ACCESS_READ |
1562 NTCREATEX_SHARE_ACCESS_WRITE |
1563 NTCREATEX_SHARE_ACCESS_DELETE;
1564 access_mask = SEC_STD_DELETE;
1565 delete_on_close = true;
1567 status = odb_can_open(lck, name->stream_id,
1568 share_access, access_mask, delete_on_close,
1569 NTCREATEX_DISP_OPEN, false);
1571 if (NT_STATUS_IS_OK(status)) {
1572 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1576 * if it's a sharing violation or we got no oplock
1577 * only keep the lock if the caller requested access
1580 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1581 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1587 } else if (!NT_STATUS_IS_OK(status)) {
1600 determine if a file can be renamed, or if it is prevented by an
1603 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1604 struct ntvfs_request *req,
1605 struct pvfs_filename *name,
1606 struct odb_lock **lckp)
1610 struct odb_lock *lck;
1611 uint32_t share_access;
1612 uint32_t access_mask;
1613 bool delete_on_close;
1615 status = pvfs_locking_key(name, name, &key);
1616 if (!NT_STATUS_IS_OK(status)) {
1617 return NT_STATUS_NO_MEMORY;
1620 lck = odb_lock(req, pvfs->odb_context, &key);
1622 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1623 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1626 share_access = NTCREATEX_SHARE_ACCESS_READ |
1627 NTCREATEX_SHARE_ACCESS_WRITE;
1628 access_mask = SEC_STD_DELETE;
1629 delete_on_close = false;
1631 status = odb_can_open(lck, name->stream_id,
1632 share_access, access_mask, delete_on_close,
1633 NTCREATEX_DISP_OPEN, false);
1636 * if it's a sharing violation or we got no oplock
1637 * only keep the lock if the caller requested access
1640 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1641 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1647 } else if (!NT_STATUS_IS_OK(status)) {
1660 determine if the file size of a file can be changed,
1661 or if it is prevented by an already open file
1663 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1664 struct ntvfs_request *req,
1665 struct pvfs_filename *name,
1666 struct odb_lock **lckp)
1670 struct odb_lock *lck;
1671 uint32_t share_access;
1672 uint32_t access_mask;
1674 bool delete_on_close;
1676 status = pvfs_locking_key(name, name, &key);
1677 if (!NT_STATUS_IS_OK(status)) {
1678 return NT_STATUS_NO_MEMORY;
1681 lck = odb_lock(req, pvfs->odb_context, &key);
1683 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1684 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1687 share_access = NTCREATEX_SHARE_ACCESS_READ |
1688 NTCREATEX_SHARE_ACCESS_WRITE |
1689 NTCREATEX_SHARE_ACCESS_DELETE;
1691 * I would have thought that we would need to pass
1692 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1694 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1695 * to set the filesize.
1699 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1700 delete_on_close = false;
1701 break_to_none = true;
1703 status = odb_can_open(lck, name->stream_id,
1704 share_access, access_mask, delete_on_close,
1705 NTCREATEX_DISP_OPEN, break_to_none);
1708 * if it's a sharing violation or we got no oplock
1709 * only keep the lock if the caller requested access
1712 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1713 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1719 } else if (!NT_STATUS_IS_OK(status)) {
1732 determine if file meta data can be accessed, or if it is prevented by an
1735 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1736 struct ntvfs_request *req,
1737 struct pvfs_filename *name)
1741 struct odb_lock *lck;
1742 uint32_t share_access;
1743 uint32_t access_mask;
1744 bool delete_on_close;
1746 status = pvfs_locking_key(name, name, &key);
1747 if (!NT_STATUS_IS_OK(status)) {
1748 return NT_STATUS_NO_MEMORY;
1751 lck = odb_lock(req, pvfs->odb_context, &key);
1753 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1754 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1757 share_access = NTCREATEX_SHARE_ACCESS_READ |
1758 NTCREATEX_SHARE_ACCESS_WRITE;
1759 access_mask = SEC_FILE_READ_ATTRIBUTE;
1760 delete_on_close = false;
1762 status = odb_can_open(lck, name->stream_id,
1763 share_access, access_mask, delete_on_close,
1764 NTCREATEX_DISP_OPEN, false);
1766 if (!NT_STATUS_IS_OK(status)) {
1775 determine if delete on close is set on
1777 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1782 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1784 if (!NT_STATUS_IS_OK(status)) {
1785 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1789 return del_on_close;