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_open_file(lck, f->handle, name->full_name, name->stream_id,
294 share_access, access_mask, del_on_close,
295 io->generic.in.open_disposition,
296 false, OPLOCK_NONE, NULL);
298 if (!NT_STATUS_IS_OK(status)) {
303 f->handle->have_opendb_entry = true;
306 DLIST_ADD(pvfs->files.list, f);
308 /* setup destructors to avoid leaks on abnormal termination */
309 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
310 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
313 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
314 mode_t mode = pvfs_fileperms(pvfs, attrib);
316 if (mkdir(name->full_name, mode) == -1) {
317 return pvfs_map_errno(pvfs,errno);
320 pvfs_xattr_unlink_hook(pvfs, name->full_name);
322 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
323 if (!NT_STATUS_IS_OK(status)) {
327 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
328 if (!NT_STATUS_IS_OK(status)) {
332 /* form the lock context used for opendb locking */
333 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
334 if (!NT_STATUS_IS_OK(status)) {
338 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
340 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
342 /* we were supposed to do a blocking lock, so something
344 return NT_STATUS_INTERNAL_DB_CORRUPTION;
347 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
348 share_access, access_mask, del_on_close,
349 io->generic.in.open_disposition,
350 false, OPLOCK_NONE, NULL);
352 if (!NT_STATUS_IS_OK(status)) {
356 f->handle->have_opendb_entry = true;
358 create_action = NTCREATEX_ACTION_CREATED;
360 notify_trigger(pvfs->notify_context,
362 FILE_NOTIFY_CHANGE_DIR_NAME,
365 create_action = NTCREATEX_ACTION_EXISTED;
369 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
372 /* the open succeeded, keep this handle permanently */
373 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
374 if (!NT_STATUS_IS_OK(status)) {
378 f->handle->open_completed = true;
380 io->generic.out.oplock_level = OPLOCK_NONE;
381 io->generic.out.file.ntvfs = h;
382 io->generic.out.create_action = create_action;
383 io->generic.out.create_time = name->dos.create_time;
384 io->generic.out.access_time = name->dos.access_time;
385 io->generic.out.write_time = name->dos.write_time;
386 io->generic.out.change_time = name->dos.change_time;
387 io->generic.out.attrib = name->dos.attrib;
388 io->generic.out.alloc_size = name->dos.alloc_size;
389 io->generic.out.size = name->st.st_size;
390 io->generic.out.file_type = FILE_TYPE_DISK;
391 io->generic.out.ipc_state = 0;
392 io->generic.out.is_directory = 1;
397 rmdir(name->full_name);
402 destroy a struct pvfs_file_handle
404 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
406 /* the write time is no longer sticky */
407 if (h->sticky_write_time) {
409 status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
410 if (NT_STATUS_IS_OK(status)) {
411 h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
412 pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
416 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
417 h->name->stream_name) {
419 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
420 if (!NT_STATUS_IS_OK(status)) {
421 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
422 h->name->stream_name, h->name->full_name));
427 if (close(h->fd) != 0) {
428 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
429 h->fd, h->name->full_name, strerror(errno)));
434 if (h->have_opendb_entry) {
435 struct odb_lock *lck;
437 const char *delete_path = NULL;
439 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
441 DEBUG(0,("Unable to lock opendb for close\n"));
445 status = odb_close_file(lck, h, &delete_path);
446 if (!NT_STATUS_IS_OK(status)) {
447 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
448 h->name->full_name, nt_errstr(status)));
451 if (h->name->stream_name == NULL &&
452 h->open_completed && delete_path) {
453 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
454 if (!NT_STATUS_IS_OK(status)) {
455 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
456 delete_path, nt_errstr(status)));
458 if (unlink(delete_path) != 0) {
459 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
460 delete_path, strerror(errno)));
462 notify_trigger(h->pvfs->notify_context,
463 NOTIFY_ACTION_REMOVED,
464 FILE_NOTIFY_CHANGE_FILE_NAME,
477 destroy a struct pvfs_file
479 static int pvfs_fnum_destructor(struct pvfs_file *f)
481 DLIST_REMOVE(f->pvfs->files.list, f);
482 pvfs_lock_close(f->pvfs, f);
483 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
490 form the lock context used for byte range locking. This is separate
491 from the locking key used for opendb locking as it needs to take
492 account of file streams (each stream is a separate byte range
495 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
496 struct pvfs_filename *name,
497 struct ntvfs_handle *ntvfs,
498 struct brl_handle **_h)
500 DATA_BLOB odb_key, key;
502 struct brl_handle *h;
504 status = pvfs_locking_key(name, mem_ctx, &odb_key);
505 NT_STATUS_NOT_OK_RETURN(status);
507 if (name->stream_name == NULL) {
510 key = data_blob_talloc(mem_ctx, NULL,
511 odb_key.length + strlen(name->stream_name) + 1);
512 NT_STATUS_HAVE_NO_MEMORY(key.data);
513 memcpy(key.data, odb_key.data, odb_key.length);
514 memcpy(key.data + odb_key.length,
515 name->stream_name, strlen(name->stream_name) + 1);
516 data_blob_free(&odb_key);
519 h = brl_create_handle(mem_ctx, ntvfs, &key);
520 NT_STATUS_HAVE_NO_MEMORY(h);
529 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
530 struct ntvfs_request *req,
531 struct pvfs_filename *name,
536 struct ntvfs_handle *h;
538 struct odb_lock *lck;
539 uint32_t create_options = io->generic.in.create_options;
540 uint32_t share_access = io->generic.in.share_access;
541 uint32_t access_mask = io->generic.in.access_mask;
545 struct pvfs_filename *parent;
546 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
548 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
549 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
550 return NT_STATUS_CANNOT_DELETE;
553 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
554 NT_STATUS_NOT_OK_RETURN(status);
556 /* check that the parent isn't opened with delete on close set */
557 status = pvfs_resolve_parent(pvfs, req, name, &parent);
558 if (NT_STATUS_IS_OK(status)) {
559 DATA_BLOB locking_key;
560 status = pvfs_locking_key(parent, req, &locking_key);
561 NT_STATUS_NOT_OK_RETURN(status);
562 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key,
564 NT_STATUS_NOT_OK_RETURN(status);
566 return NT_STATUS_DELETE_PENDING;
570 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
576 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
577 NT_STATUS_NOT_OK_RETURN(status);
579 f = talloc(h, struct pvfs_file);
580 NT_STATUS_HAVE_NO_MEMORY(f);
582 f->handle = talloc(f, struct pvfs_file_handle);
583 NT_STATUS_HAVE_NO_MEMORY(f->handle);
585 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
586 mode = pvfs_fileperms(pvfs, attrib);
588 /* create the file */
589 fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
591 return pvfs_map_errno(pvfs, errno);
594 pvfs_xattr_unlink_hook(pvfs, name->full_name);
596 /* if this was a stream create then create the stream as well */
597 if (name->stream_name) {
598 status = pvfs_stream_create(pvfs, name, fd);
599 if (!NT_STATUS_IS_OK(status)) {
605 /* re-resolve the open fd */
606 status = pvfs_resolve_name_fd(pvfs, fd, name);
607 if (!NT_STATUS_IS_OK(status)) {
612 name->dos.attrib = attrib;
613 status = pvfs_dosattrib_save(pvfs, name, fd);
614 if (!NT_STATUS_IS_OK(status)) {
619 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
620 if (!NT_STATUS_IS_OK(status)) {
624 /* form the lock context used for byte range locking and
626 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
627 if (!NT_STATUS_IS_OK(status)) {
631 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
632 if (!NT_STATUS_IS_OK(status)) {
636 /* grab a lock on the open file record */
637 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
639 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
641 /* we were supposed to do a blocking lock, so something
643 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
647 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
650 del_on_close = false;
653 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
654 oplock_level = OPLOCK_NONE;
655 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
656 oplock_level = OPLOCK_BATCH;
657 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
658 oplock_level = OPLOCK_EXCLUSIVE;
661 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
662 share_access, access_mask, del_on_close,
663 io->generic.in.open_disposition,
664 false, oplock_level, &oplock_granted);
666 if (!NT_STATUS_IS_OK(status)) {
667 /* bad news, we must have hit a race - we don't delete the file
668 here as the most likely scenario is that someone else created
669 the file at the same time */
677 f->pending_list = NULL;
679 f->share_access = io->generic.in.share_access;
680 f->access_mask = access_mask;
681 f->impersonation = io->generic.in.impersonation;
682 f->notify_buffer = NULL;
685 f->handle->pvfs = pvfs;
686 f->handle->name = talloc_steal(f->handle, name);
688 f->handle->create_options = io->generic.in.create_options;
689 f->handle->seek_offset = 0;
690 f->handle->position = 0;
692 f->handle->oplock = NULL;
693 f->handle->have_opendb_entry = true;
694 f->handle->sticky_write_time = false;
695 f->handle->open_completed = false;
697 DLIST_ADD(pvfs->files.list, f);
699 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
700 oplock_granted = OPLOCK_BATCH;
701 } else if (oplock_granted != OPLOCK_NONE) {
702 status = pvfs_setup_oplock(f, oplock_granted);
703 if (!NT_STATUS_IS_OK(status)) {
709 /* setup a destructor to avoid file descriptor leaks on
710 abnormal termination */
711 talloc_set_destructor(f, pvfs_fnum_destructor);
712 talloc_set_destructor(f->handle, pvfs_handle_destructor);
714 io->generic.out.oplock_level = oplock_granted;
715 io->generic.out.file.ntvfs = f->ntvfs;
716 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
717 io->generic.out.create_time = name->dos.create_time;
718 io->generic.out.access_time = name->dos.access_time;
719 io->generic.out.write_time = name->dos.write_time;
720 io->generic.out.change_time = name->dos.change_time;
721 io->generic.out.attrib = name->dos.attrib;
722 io->generic.out.alloc_size = name->dos.alloc_size;
723 io->generic.out.size = name->st.st_size;
724 io->generic.out.file_type = FILE_TYPE_DISK;
725 io->generic.out.ipc_state = 0;
726 io->generic.out.is_directory = 0;
728 /* success - keep the file handle */
729 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
730 if (!NT_STATUS_IS_OK(status)) {
734 f->handle->open_completed = true;
736 notify_trigger(pvfs->notify_context,
738 FILE_NOTIFY_CHANGE_FILE_NAME,
745 unlink(name->full_name);
750 state of a pending retry
752 struct pvfs_odb_retry {
753 struct ntvfs_module_context *ntvfs;
754 struct ntvfs_request *req;
755 DATA_BLOB odb_locking_key;
758 void (*callback)(struct pvfs_odb_retry *r,
759 struct ntvfs_module_context *ntvfs,
760 struct ntvfs_request *req,
763 enum pvfs_wait_notice reason);
766 /* destroy a pending request */
767 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
769 struct pvfs_state *pvfs = r->ntvfs->private_data;
770 if (r->odb_locking_key.data) {
771 struct odb_lock *lck;
772 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
774 odb_remove_pending(lck, r);
781 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
783 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
785 if (reason == PVFS_WAIT_EVENT) {
787 * The pending odb entry is already removed.
788 * We use a null locking key to indicate this
791 data_blob_free(&r->odb_locking_key);
794 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
798 setup for a retry of a request that was rejected
799 by odb_open_file() or odb_can_open()
801 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
802 struct ntvfs_request *req,
803 struct odb_lock *lck,
804 struct timeval end_time,
807 void (*callback)(struct pvfs_odb_retry *r,
808 struct ntvfs_module_context *ntvfs,
809 struct ntvfs_request *req,
812 enum pvfs_wait_notice reason))
814 struct pvfs_state *pvfs = ntvfs->private_data;
815 struct pvfs_odb_retry *r;
816 struct pvfs_wait *wait_handle;
819 r = talloc(req, struct pvfs_odb_retry);
820 NT_STATUS_HAVE_NO_MEMORY(r);
825 r->private_data = private_data;
826 r->callback = callback;
827 r->odb_locking_key = odb_get_key(r, lck);
828 if (r->odb_locking_key.data == NULL) {
829 return NT_STATUS_NO_MEMORY;
832 /* setup a pending lock */
833 status = odb_open_file_pending(lck, r);
834 if (!NT_STATUS_IS_OK(status)) {
840 talloc_set_destructor(r, pvfs_odb_retry_destructor);
842 wait_handle = pvfs_wait_message(pvfs, req,
843 MSG_PVFS_RETRY_OPEN, end_time,
844 pvfs_odb_retry_callback, r);
845 if (wait_handle == NULL) {
846 return NT_STATUS_NO_MEMORY;
849 talloc_steal(r, wait_handle);
851 talloc_steal(pvfs, r);
857 retry an open after a sharing violation
859 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
860 struct ntvfs_module_context *ntvfs,
861 struct ntvfs_request *req,
864 enum pvfs_wait_notice reason)
866 union smb_open *io = talloc_get_type(_io, union smb_open);
869 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
870 just a bug in their server, but we better do the same */
871 if (reason == PVFS_WAIT_CANCEL) {
875 if (reason == PVFS_WAIT_TIMEOUT) {
876 /* if it timed out, then give the failure
879 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
880 req->async_states->send_fn(req);
886 /* try the open again, which could trigger another retry setup
887 if it wants to, so we have to unmark the async flag so we
888 will know if it does a second async reply */
889 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
891 status = pvfs_open(ntvfs, req, io);
892 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
893 /* the 2nd try also replied async, so we don't send
898 /* re-mark it async, just in case someone up the chain does
900 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
902 /* send the reply up the chain */
903 req->async_states->status = status;
904 req->async_states->send_fn(req);
909 special handling for openx DENY_DOS semantics
911 This function attempts a reference open using an existing handle. If its allowed,
912 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
913 open processing continues.
915 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
916 struct ntvfs_request *req, union smb_open *io,
917 struct pvfs_file *f, struct odb_lock *lck)
919 struct pvfs_state *pvfs = ntvfs->private_data;
920 struct pvfs_file *f2;
921 struct pvfs_filename *name;
924 /* search for an existing open with the right parameters. Note
925 the magic ntcreatex options flag, which is set in the
926 generic mapping code. This might look ugly, but its
927 actually pretty much now w2k does it internally as well.
929 If you look at the BASE-DENYDOS test you will see that a
930 DENY_DOS is a very special case, and in the right
931 circumstances you actually get the _same_ handle back
932 twice, rather than a new handle.
934 for (f2=pvfs->files.list;f2;f2=f2->next) {
936 f2->ntvfs->session_info == req->session_info &&
937 f2->ntvfs->smbpid == req->smbpid &&
938 (f2->handle->create_options &
939 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
940 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
941 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
942 strcasecmp_m(f2->handle->name->original_name,
943 io->generic.in.fname)==0) {
949 return NT_STATUS_SHARING_VIOLATION;
952 /* quite an insane set of semantics ... */
953 if (is_exe_filename(io->generic.in.fname) &&
954 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
955 return NT_STATUS_SHARING_VIOLATION;
959 setup a reference to the existing handle
961 talloc_free(f->handle);
962 f->handle = talloc_reference(f, f2->handle);
966 name = f->handle->name;
968 io->generic.out.oplock_level = OPLOCK_NONE;
969 io->generic.out.file.ntvfs = f->ntvfs;
970 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
971 io->generic.out.create_time = name->dos.create_time;
972 io->generic.out.access_time = name->dos.access_time;
973 io->generic.out.write_time = name->dos.write_time;
974 io->generic.out.change_time = name->dos.change_time;
975 io->generic.out.attrib = name->dos.attrib;
976 io->generic.out.alloc_size = name->dos.alloc_size;
977 io->generic.out.size = name->st.st_size;
978 io->generic.out.file_type = FILE_TYPE_DISK;
979 io->generic.out.ipc_state = 0;
980 io->generic.out.is_directory = 0;
982 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
983 NT_STATUS_NOT_OK_RETURN(status);
991 setup for a open retry after a sharing violation
993 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
994 struct ntvfs_request *req,
997 struct odb_lock *lck,
998 NTSTATUS parent_status)
1000 struct pvfs_state *pvfs = ntvfs->private_data;
1002 struct timeval end_time;
1004 if (io->generic.in.create_options &
1005 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1006 /* see if we can satisfy the request using the special DENY_DOS
1008 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1009 if (NT_STATUS_IS_OK(status)) {
1014 /* the retry should allocate a new file handle */
1017 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1018 end_time = timeval_add(&req->statistics.request_time,
1019 0, pvfs->sharing_violation_delay);
1020 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1021 end_time = timeval_add(&req->statistics.request_time,
1022 pvfs->oplock_break_timeout, 0);
1024 return NT_STATUS_INTERNAL_ERROR;
1027 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
1028 pvfs_retry_open_sharing);
1034 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1035 struct ntvfs_request *req, union smb_open *io)
1037 struct pvfs_state *pvfs = ntvfs->private_data;
1039 struct pvfs_filename *name;
1040 struct pvfs_file *f;
1041 struct ntvfs_handle *h;
1044 struct odb_lock *lck;
1045 uint32_t create_options;
1046 uint32_t share_access;
1047 uint32_t access_mask;
1049 bool stream_existed, stream_truncate=false;
1050 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1052 /* use the generic mapping code to avoid implementing all the
1053 different open calls. */
1054 if (io->generic.level != RAW_OPEN_GENERIC &&
1055 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1056 return ntvfs_map_open(ntvfs, req, io);
1059 /* resolve the cifs name to a posix name */
1060 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1061 PVFS_RESOLVE_STREAMS, &name);
1062 if (!NT_STATUS_IS_OK(status)) {
1066 /* directory opens are handled separately */
1067 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1068 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1069 return pvfs_open_directory(pvfs, req, name, io);
1072 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1073 open doesn't match */
1074 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1076 create_options = io->generic.in.create_options;
1077 share_access = io->generic.in.share_access;
1078 access_mask = io->generic.in.access_mask;
1080 /* certain create options are not allowed */
1081 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1082 !(access_mask & SEC_STD_DELETE)) {
1083 return NT_STATUS_INVALID_PARAMETER;
1088 switch (io->generic.in.open_disposition) {
1089 case NTCREATEX_DISP_SUPERSEDE:
1090 case NTCREATEX_DISP_OVERWRITE_IF:
1091 if (name->stream_name == NULL) {
1094 stream_truncate = true;
1098 case NTCREATEX_DISP_OPEN:
1099 if (!name->stream_exists) {
1100 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1105 case NTCREATEX_DISP_OVERWRITE:
1106 if (!name->stream_exists) {
1107 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1109 if (name->stream_name == NULL) {
1112 stream_truncate = true;
1116 case NTCREATEX_DISP_CREATE:
1117 if (name->stream_exists) {
1118 return NT_STATUS_OBJECT_NAME_COLLISION;
1123 case NTCREATEX_DISP_OPEN_IF:
1128 return NT_STATUS_INVALID_PARAMETER;
1131 /* handle creating a new file separately */
1132 if (!name->exists) {
1133 status = pvfs_create_file(pvfs, req, name, io);
1134 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1138 /* we've hit a race - the file was created during this call */
1139 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1143 /* try re-resolving the name */
1144 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1145 if (!NT_STATUS_IS_OK(status)) {
1148 /* fall through to a normal open */
1151 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1152 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1153 return NT_STATUS_CANNOT_DELETE;
1156 /* check the security descriptor */
1157 status = pvfs_access_check(pvfs, req, name, &access_mask);
1158 if (!NT_STATUS_IS_OK(status)) {
1162 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1163 NT_STATUS_NOT_OK_RETURN(status);
1165 f = talloc(h, struct pvfs_file);
1167 return NT_STATUS_NO_MEMORY;
1170 f->handle = talloc(f, struct pvfs_file_handle);
1171 if (f->handle == NULL) {
1172 return NT_STATUS_NO_MEMORY;
1177 f->pending_list = NULL;
1179 f->share_access = io->generic.in.share_access;
1180 f->access_mask = access_mask;
1181 f->impersonation = io->generic.in.impersonation;
1182 f->notify_buffer = NULL;
1185 f->handle->pvfs = pvfs;
1187 f->handle->name = talloc_steal(f->handle, name);
1188 f->handle->create_options = io->generic.in.create_options;
1189 f->handle->seek_offset = 0;
1190 f->handle->position = 0;
1191 f->handle->mode = 0;
1192 f->handle->oplock = NULL;
1193 f->handle->have_opendb_entry = false;
1194 f->handle->sticky_write_time = false;
1195 f->handle->open_completed = false;
1197 /* form the lock context used for byte range locking and
1199 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1200 if (!NT_STATUS_IS_OK(status)) {
1204 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1205 if (!NT_STATUS_IS_OK(status)) {
1209 /* get a lock on this file before the actual open */
1210 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1212 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1214 /* we were supposed to do a blocking lock, so something
1216 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1219 DLIST_ADD(pvfs->files.list, f);
1221 /* setup a destructor to avoid file descriptor leaks on
1222 abnormal termination */
1223 talloc_set_destructor(f, pvfs_fnum_destructor);
1224 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1227 * Only SMB2 takes care of the delete_on_close,
1230 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1231 req->ctx->protocol == PROTOCOL_SMB2) {
1232 del_on_close = true;
1234 del_on_close = false;
1237 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1238 oplock_level = OPLOCK_NONE;
1239 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1240 oplock_level = OPLOCK_BATCH;
1241 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1242 oplock_level = OPLOCK_EXCLUSIVE;
1245 /* see if we are allowed to open at the same time as existing opens */
1246 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
1247 share_access, access_mask, del_on_close,
1248 io->generic.in.open_disposition,
1249 false, oplock_level, &oplock_granted);
1252 * on a sharing violation we need to retry when the file is closed by
1253 * the other user, or after 1 second
1254 * on a non granted oplock we need to retry when the file is closed by
1255 * the other user, or after 30 seconds
1257 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1258 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1259 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1260 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1263 if (!NT_STATUS_IS_OK(status)) {
1268 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1269 oplock_granted = OPLOCK_BATCH;
1270 } else if (oplock_granted != OPLOCK_NONE) {
1271 status = pvfs_setup_oplock(f, oplock_granted);
1272 if (!NT_STATUS_IS_OK(status)) {
1278 f->handle->have_opendb_entry = true;
1280 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1286 /* do the actual open */
1287 fd = open(f->handle->name->full_name, flags);
1290 return pvfs_map_errno(f->pvfs, errno);
1295 stream_existed = name->stream_exists;
1297 /* if this was a stream create then create the stream as well */
1298 if (!name->stream_exists) {
1299 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1300 if (!NT_STATUS_IS_OK(status)) {
1304 if (stream_truncate) {
1305 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1306 if (!NT_STATUS_IS_OK(status)) {
1313 /* re-resolve the open fd */
1314 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1315 if (!NT_STATUS_IS_OK(status)) {
1320 if (f->handle->name->stream_id == 0 &&
1321 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1322 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1323 /* for overwrite we need to replace file permissions */
1324 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1325 mode_t mode = pvfs_fileperms(pvfs, attrib);
1326 if (fchmod(fd, mode) == -1) {
1328 return pvfs_map_errno(pvfs, errno);
1330 name->dos.attrib = attrib;
1331 status = pvfs_dosattrib_save(pvfs, name, fd);
1332 if (!NT_STATUS_IS_OK(status)) {
1340 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1341 NT_STATUS_NOT_OK_RETURN(status);
1343 /* mark the open as having completed fully, so delete on close
1345 f->handle->open_completed = true;
1347 io->generic.out.oplock_level = oplock_granted;
1348 io->generic.out.file.ntvfs = h;
1349 io->generic.out.create_action = stream_existed?
1350 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1351 io->generic.out.create_time = name->dos.create_time;
1352 io->generic.out.access_time = name->dos.access_time;
1353 io->generic.out.write_time = name->dos.write_time;
1354 io->generic.out.change_time = name->dos.change_time;
1355 io->generic.out.attrib = name->dos.attrib;
1356 io->generic.out.alloc_size = name->dos.alloc_size;
1357 io->generic.out.size = name->st.st_size;
1358 io->generic.out.file_type = FILE_TYPE_DISK;
1359 io->generic.out.ipc_state = 0;
1360 io->generic.out.is_directory = 0;
1362 return NT_STATUS_OK;
1369 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1370 struct ntvfs_request *req, union smb_close *io)
1372 struct pvfs_state *pvfs = ntvfs->private_data;
1373 struct pvfs_file *f;
1374 struct utimbuf unix_times;
1376 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1377 return NT_STATUS_DOS(ERRSRV, ERRerror);
1380 if (io->generic.level != RAW_CLOSE_CLOSE) {
1381 return ntvfs_map_close(ntvfs, req, io);
1384 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1386 return NT_STATUS_INVALID_HANDLE;
1389 if (!null_time(io->close.in.write_time)) {
1390 unix_times.actime = 0;
1391 unix_times.modtime = io->close.in.write_time;
1392 utime(f->handle->name->full_name, &unix_times);
1393 } else if (f->handle->sticky_write_time) {
1394 unix_times.actime = 0;
1395 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1396 utime(f->handle->name->full_name, &unix_times);
1401 return NT_STATUS_OK;
1406 logoff - close all file descriptors open by a vuid
1408 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1409 struct ntvfs_request *req)
1411 struct pvfs_state *pvfs = ntvfs->private_data;
1412 struct pvfs_file *f, *next;
1414 for (f=pvfs->files.list;f;f=next) {
1416 if (f->ntvfs->session_info == req->session_info) {
1421 return NT_STATUS_OK;
1426 exit - close files for the current pid
1428 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1429 struct ntvfs_request *req)
1431 struct pvfs_state *pvfs = ntvfs->private_data;
1432 struct pvfs_file *f, *next;
1434 for (f=pvfs->files.list;f;f=next) {
1436 if (f->ntvfs->session_info == req->session_info &&
1437 f->ntvfs->smbpid == req->smbpid) {
1442 return NT_STATUS_OK;
1447 change the delete on close flag on an already open file
1449 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1450 struct ntvfs_request *req,
1451 struct pvfs_file *f, bool del_on_close)
1453 struct odb_lock *lck;
1456 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1457 return NT_STATUS_CANNOT_DELETE;
1460 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1461 !pvfs_directory_empty(pvfs, f->handle->name)) {
1462 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1466 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1468 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1471 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1473 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1476 status = odb_set_delete_on_close(lck, del_on_close);
1485 determine if a file can be deleted, or if it is prevented by an
1488 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1489 struct ntvfs_request *req,
1490 struct pvfs_filename *name,
1491 struct odb_lock **lckp)
1495 struct odb_lock *lck;
1496 uint32_t share_access;
1497 uint32_t access_mask;
1498 bool delete_on_close;
1500 status = pvfs_locking_key(name, name, &key);
1501 if (!NT_STATUS_IS_OK(status)) {
1502 return NT_STATUS_NO_MEMORY;
1505 lck = odb_lock(req, pvfs->odb_context, &key);
1507 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1508 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1511 share_access = NTCREATEX_SHARE_ACCESS_READ |
1512 NTCREATEX_SHARE_ACCESS_WRITE |
1513 NTCREATEX_SHARE_ACCESS_DELETE;
1514 access_mask = SEC_STD_DELETE;
1515 delete_on_close = true;
1517 status = odb_can_open(lck, name->stream_id,
1518 share_access, access_mask, delete_on_close,
1519 NTCREATEX_DISP_OPEN, false);
1521 if (NT_STATUS_IS_OK(status)) {
1522 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1526 * if it's a sharing violation or we got no oplock
1527 * only keep the lock if the caller requested access
1530 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1531 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1537 } else if (!NT_STATUS_IS_OK(status)) {
1550 determine if a file can be renamed, or if it is prevented by an
1553 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1554 struct ntvfs_request *req,
1555 struct pvfs_filename *name,
1556 struct odb_lock **lckp)
1560 struct odb_lock *lck;
1561 uint32_t share_access;
1562 uint32_t access_mask;
1563 bool delete_on_close;
1565 status = pvfs_locking_key(name, name, &key);
1566 if (!NT_STATUS_IS_OK(status)) {
1567 return NT_STATUS_NO_MEMORY;
1570 lck = odb_lock(req, pvfs->odb_context, &key);
1572 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1573 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1576 share_access = NTCREATEX_SHARE_ACCESS_READ |
1577 NTCREATEX_SHARE_ACCESS_WRITE;
1578 access_mask = SEC_STD_DELETE;
1579 delete_on_close = false;
1581 status = odb_can_open(lck, name->stream_id,
1582 share_access, access_mask, delete_on_close,
1583 NTCREATEX_DISP_OPEN, false);
1586 * if it's a sharing violation or we got no oplock
1587 * only keep the lock if the caller requested access
1590 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1591 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1597 } else if (!NT_STATUS_IS_OK(status)) {
1610 determine if the file size of a file can be changed,
1611 or if it is prevented by an already open file
1613 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1614 struct ntvfs_request *req,
1615 struct pvfs_filename *name,
1616 struct odb_lock **lckp)
1620 struct odb_lock *lck;
1621 uint32_t share_access;
1622 uint32_t access_mask;
1624 bool delete_on_close;
1626 status = pvfs_locking_key(name, name, &key);
1627 if (!NT_STATUS_IS_OK(status)) {
1628 return NT_STATUS_NO_MEMORY;
1631 lck = odb_lock(req, pvfs->odb_context, &key);
1633 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1634 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1637 share_access = NTCREATEX_SHARE_ACCESS_READ |
1638 NTCREATEX_SHARE_ACCESS_WRITE |
1639 NTCREATEX_SHARE_ACCESS_DELETE;
1641 * I would have thought that we would need to pass
1642 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1644 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1645 * to set the filesize.
1649 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1650 delete_on_close = false;
1651 break_to_none = true;
1653 status = odb_can_open(lck, name->stream_id,
1654 share_access, access_mask, delete_on_close,
1655 NTCREATEX_DISP_OPEN, break_to_none);
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 file meta data can be accessed, or if it is prevented by an
1685 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1686 struct ntvfs_request *req,
1687 struct pvfs_filename *name)
1691 struct odb_lock *lck;
1692 uint32_t share_access;
1693 uint32_t access_mask;
1694 bool delete_on_close;
1696 status = pvfs_locking_key(name, name, &key);
1697 if (!NT_STATUS_IS_OK(status)) {
1698 return NT_STATUS_NO_MEMORY;
1701 lck = odb_lock(req, pvfs->odb_context, &key);
1703 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1704 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1707 share_access = NTCREATEX_SHARE_ACCESS_READ |
1708 NTCREATEX_SHARE_ACCESS_WRITE;
1709 access_mask = SEC_FILE_READ_ATTRIBUTE;
1710 delete_on_close = false;
1712 status = odb_can_open(lck, name->stream_id,
1713 share_access, access_mask, delete_on_close,
1714 NTCREATEX_DISP_OPEN, false);
1716 if (!NT_STATUS_IS_OK(status)) {
1725 determine if delete on close is set on
1727 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1732 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1734 if (!NT_STATUS_IS_OK(status)) {
1735 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1739 return del_on_close;