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, 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, 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;
547 bool allow_level_II_oplock = false;
549 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
550 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
551 return NT_STATUS_CANNOT_DELETE;
554 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
555 NT_STATUS_NOT_OK_RETURN(status);
557 /* check that the parent isn't opened with delete on close set */
558 status = pvfs_resolve_parent(pvfs, req, name, &parent);
559 if (NT_STATUS_IS_OK(status)) {
560 DATA_BLOB locking_key;
561 status = pvfs_locking_key(parent, req, &locking_key);
562 NT_STATUS_NOT_OK_RETURN(status);
563 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key,
565 NT_STATUS_NOT_OK_RETURN(status);
567 return NT_STATUS_DELETE_PENDING;
571 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
577 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
578 NT_STATUS_NOT_OK_RETURN(status);
580 f = talloc(h, struct pvfs_file);
581 NT_STATUS_HAVE_NO_MEMORY(f);
583 f->handle = talloc(f, struct pvfs_file_handle);
584 NT_STATUS_HAVE_NO_MEMORY(f->handle);
586 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
587 mode = pvfs_fileperms(pvfs, attrib);
589 /* create the file */
590 fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
592 return pvfs_map_errno(pvfs, errno);
595 pvfs_xattr_unlink_hook(pvfs, name->full_name);
597 /* if this was a stream create then create the stream as well */
598 if (name->stream_name) {
599 status = pvfs_stream_create(pvfs, name, fd);
600 if (!NT_STATUS_IS_OK(status)) {
606 /* re-resolve the open fd */
607 status = pvfs_resolve_name_fd(pvfs, fd, name);
608 if (!NT_STATUS_IS_OK(status)) {
613 name->dos.attrib = attrib;
614 status = pvfs_dosattrib_save(pvfs, name, fd);
615 if (!NT_STATUS_IS_OK(status)) {
620 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
621 if (!NT_STATUS_IS_OK(status)) {
625 /* form the lock context used for byte range locking and
627 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
628 if (!NT_STATUS_IS_OK(status)) {
632 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
633 if (!NT_STATUS_IS_OK(status)) {
637 /* grab a lock on the open file record */
638 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
640 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
642 /* we were supposed to do a blocking lock, so something
644 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
648 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
651 del_on_close = false;
654 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
655 oplock_level = OPLOCK_NONE;
656 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
657 oplock_level = OPLOCK_BATCH;
658 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
659 oplock_level = OPLOCK_EXCLUSIVE;
662 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
663 allow_level_II_oplock = true;
666 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
667 share_access, access_mask, del_on_close,
668 io->generic.in.open_disposition,
669 false, allow_level_II_oplock,
670 oplock_level, &oplock_granted);
672 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 */
683 f->pending_list = NULL;
685 f->share_access = io->generic.in.share_access;
686 f->access_mask = access_mask;
687 f->impersonation = io->generic.in.impersonation;
688 f->notify_buffer = NULL;
691 f->handle->pvfs = pvfs;
692 f->handle->name = talloc_steal(f->handle, name);
694 f->handle->create_options = io->generic.in.create_options;
695 f->handle->seek_offset = 0;
696 f->handle->position = 0;
698 f->handle->oplock = NULL;
699 f->handle->have_opendb_entry = true;
700 f->handle->sticky_write_time = false;
701 f->handle->open_completed = false;
703 DLIST_ADD(pvfs->files.list, f);
705 /* setup a destructor to avoid file descriptor leaks on
706 abnormal termination */
707 talloc_set_destructor(f, pvfs_fnum_destructor);
708 talloc_set_destructor(f->handle, pvfs_handle_destructor);
710 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
711 oplock_granted = OPLOCK_BATCH;
712 } else if (oplock_granted != OPLOCK_NONE) {
713 status = pvfs_setup_oplock(f, oplock_granted);
714 if (!NT_STATUS_IS_OK(status)) {
719 io->generic.out.oplock_level = oplock_granted;
720 io->generic.out.file.ntvfs = f->ntvfs;
721 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
722 io->generic.out.create_time = name->dos.create_time;
723 io->generic.out.access_time = name->dos.access_time;
724 io->generic.out.write_time = name->dos.write_time;
725 io->generic.out.change_time = name->dos.change_time;
726 io->generic.out.attrib = name->dos.attrib;
727 io->generic.out.alloc_size = name->dos.alloc_size;
728 io->generic.out.size = name->st.st_size;
729 io->generic.out.file_type = FILE_TYPE_DISK;
730 io->generic.out.ipc_state = 0;
731 io->generic.out.is_directory = 0;
733 /* success - keep the file handle */
734 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
735 if (!NT_STATUS_IS_OK(status)) {
739 f->handle->open_completed = true;
741 notify_trigger(pvfs->notify_context,
743 FILE_NOTIFY_CHANGE_FILE_NAME,
750 unlink(name->full_name);
755 state of a pending retry
757 struct pvfs_odb_retry {
758 struct ntvfs_module_context *ntvfs;
759 struct ntvfs_request *req;
760 DATA_BLOB odb_locking_key;
763 void (*callback)(struct pvfs_odb_retry *r,
764 struct ntvfs_module_context *ntvfs,
765 struct ntvfs_request *req,
768 enum pvfs_wait_notice reason);
771 /* destroy a pending request */
772 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
774 struct pvfs_state *pvfs = r->ntvfs->private_data;
775 if (r->odb_locking_key.data) {
776 struct odb_lock *lck;
777 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
779 odb_remove_pending(lck, r);
786 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
788 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
790 if (reason == PVFS_WAIT_EVENT) {
792 * The pending odb entry is already removed.
793 * We use a null locking key to indicate this
796 data_blob_free(&r->odb_locking_key);
799 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
803 setup for a retry of a request that was rejected
804 by odb_open_file() or odb_can_open()
806 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
807 struct ntvfs_request *req,
808 struct odb_lock *lck,
809 struct timeval end_time,
812 void (*callback)(struct pvfs_odb_retry *r,
813 struct ntvfs_module_context *ntvfs,
814 struct ntvfs_request *req,
817 enum pvfs_wait_notice reason))
819 struct pvfs_state *pvfs = ntvfs->private_data;
820 struct pvfs_odb_retry *r;
821 struct pvfs_wait *wait_handle;
824 r = talloc(req, struct pvfs_odb_retry);
825 NT_STATUS_HAVE_NO_MEMORY(r);
830 r->private_data = private_data;
831 r->callback = callback;
832 r->odb_locking_key = odb_get_key(r, lck);
833 if (r->odb_locking_key.data == NULL) {
834 return NT_STATUS_NO_MEMORY;
837 /* setup a pending lock */
838 status = odb_open_file_pending(lck, r);
839 if (!NT_STATUS_IS_OK(status)) {
845 talloc_set_destructor(r, pvfs_odb_retry_destructor);
847 wait_handle = pvfs_wait_message(pvfs, req,
848 MSG_PVFS_RETRY_OPEN, end_time,
849 pvfs_odb_retry_callback, r);
850 if (wait_handle == NULL) {
851 return NT_STATUS_NO_MEMORY;
854 talloc_steal(r, wait_handle);
856 talloc_steal(pvfs, r);
862 retry an open after a sharing violation
864 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
865 struct ntvfs_module_context *ntvfs,
866 struct ntvfs_request *req,
869 enum pvfs_wait_notice reason)
871 union smb_open *io = talloc_get_type(_io, union smb_open);
874 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
875 just a bug in their server, but we better do the same */
876 if (reason == PVFS_WAIT_CANCEL) {
880 if (reason == PVFS_WAIT_TIMEOUT) {
881 /* if it timed out, then give the failure
884 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
885 req->async_states->send_fn(req);
891 /* try the open again, which could trigger another retry setup
892 if it wants to, so we have to unmark the async flag so we
893 will know if it does a second async reply */
894 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
896 status = pvfs_open(ntvfs, req, io);
897 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
898 /* the 2nd try also replied async, so we don't send
903 /* re-mark it async, just in case someone up the chain does
905 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
907 /* send the reply up the chain */
908 req->async_states->status = status;
909 req->async_states->send_fn(req);
914 special handling for openx DENY_DOS semantics
916 This function attempts a reference open using an existing handle. If its allowed,
917 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
918 open processing continues.
920 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
921 struct ntvfs_request *req, union smb_open *io,
922 struct pvfs_file *f, struct odb_lock *lck)
924 struct pvfs_state *pvfs = ntvfs->private_data;
925 struct pvfs_file *f2;
926 struct pvfs_filename *name;
929 /* search for an existing open with the right parameters. Note
930 the magic ntcreatex options flag, which is set in the
931 generic mapping code. This might look ugly, but its
932 actually pretty much now w2k does it internally as well.
934 If you look at the BASE-DENYDOS test you will see that a
935 DENY_DOS is a very special case, and in the right
936 circumstances you actually get the _same_ handle back
937 twice, rather than a new handle.
939 for (f2=pvfs->files.list;f2;f2=f2->next) {
941 f2->ntvfs->session_info == req->session_info &&
942 f2->ntvfs->smbpid == req->smbpid &&
943 (f2->handle->create_options &
944 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
945 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
946 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
947 strcasecmp_m(f2->handle->name->original_name,
948 io->generic.in.fname)==0) {
954 return NT_STATUS_SHARING_VIOLATION;
957 /* quite an insane set of semantics ... */
958 if (is_exe_filename(io->generic.in.fname) &&
959 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
960 return NT_STATUS_SHARING_VIOLATION;
964 setup a reference to the existing handle
966 talloc_free(f->handle);
967 f->handle = talloc_reference(f, f2->handle);
971 name = f->handle->name;
973 io->generic.out.oplock_level = OPLOCK_NONE;
974 io->generic.out.file.ntvfs = f->ntvfs;
975 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
976 io->generic.out.create_time = name->dos.create_time;
977 io->generic.out.access_time = name->dos.access_time;
978 io->generic.out.write_time = name->dos.write_time;
979 io->generic.out.change_time = name->dos.change_time;
980 io->generic.out.attrib = name->dos.attrib;
981 io->generic.out.alloc_size = name->dos.alloc_size;
982 io->generic.out.size = name->st.st_size;
983 io->generic.out.file_type = FILE_TYPE_DISK;
984 io->generic.out.ipc_state = 0;
985 io->generic.out.is_directory = 0;
987 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
988 NT_STATUS_NOT_OK_RETURN(status);
996 setup for a open retry after a sharing violation
998 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
999 struct ntvfs_request *req,
1001 struct pvfs_file *f,
1002 struct odb_lock *lck,
1003 NTSTATUS parent_status)
1005 struct pvfs_state *pvfs = ntvfs->private_data;
1007 struct timeval end_time;
1009 if (io->generic.in.create_options &
1010 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1011 /* see if we can satisfy the request using the special DENY_DOS
1013 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1014 if (NT_STATUS_IS_OK(status)) {
1019 /* the retry should allocate a new file handle */
1022 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1023 end_time = timeval_add(&req->statistics.request_time,
1024 0, pvfs->sharing_violation_delay);
1025 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1026 end_time = timeval_add(&req->statistics.request_time,
1027 pvfs->oplock_break_timeout, 0);
1029 return NT_STATUS_INTERNAL_ERROR;
1032 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
1033 pvfs_retry_open_sharing);
1039 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1040 struct ntvfs_request *req, union smb_open *io)
1042 struct pvfs_state *pvfs = ntvfs->private_data;
1044 struct pvfs_filename *name;
1045 struct pvfs_file *f;
1046 struct ntvfs_handle *h;
1049 struct odb_lock *lck;
1050 uint32_t create_options;
1051 uint32_t share_access;
1052 uint32_t access_mask;
1054 bool stream_existed, stream_truncate=false;
1055 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1056 bool allow_level_II_oplock = false;
1058 /* use the generic mapping code to avoid implementing all the
1059 different open calls. */
1060 if (io->generic.level != RAW_OPEN_GENERIC &&
1061 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1062 return ntvfs_map_open(ntvfs, req, io);
1065 /* resolve the cifs name to a posix name */
1066 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1067 PVFS_RESOLVE_STREAMS, &name);
1068 if (!NT_STATUS_IS_OK(status)) {
1072 /* directory opens are handled separately */
1073 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1074 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1075 return pvfs_open_directory(pvfs, req, name, io);
1078 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1079 open doesn't match */
1080 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1082 create_options = io->generic.in.create_options;
1083 share_access = io->generic.in.share_access;
1084 access_mask = io->generic.in.access_mask;
1086 /* certain create options are not allowed */
1087 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1088 !(access_mask & SEC_STD_DELETE)) {
1089 return NT_STATUS_INVALID_PARAMETER;
1094 switch (io->generic.in.open_disposition) {
1095 case NTCREATEX_DISP_SUPERSEDE:
1096 case NTCREATEX_DISP_OVERWRITE_IF:
1097 if (name->stream_name == NULL) {
1100 stream_truncate = true;
1104 case NTCREATEX_DISP_OPEN:
1105 if (!name->stream_exists) {
1106 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1111 case NTCREATEX_DISP_OVERWRITE:
1112 if (!name->stream_exists) {
1113 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1115 if (name->stream_name == NULL) {
1118 stream_truncate = true;
1122 case NTCREATEX_DISP_CREATE:
1123 if (name->stream_exists) {
1124 return NT_STATUS_OBJECT_NAME_COLLISION;
1129 case NTCREATEX_DISP_OPEN_IF:
1134 return NT_STATUS_INVALID_PARAMETER;
1137 /* handle creating a new file separately */
1138 if (!name->exists) {
1139 status = pvfs_create_file(pvfs, req, name, io);
1140 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1144 /* we've hit a race - the file was created during this call */
1145 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1149 /* try re-resolving the name */
1150 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1151 if (!NT_STATUS_IS_OK(status)) {
1154 /* fall through to a normal open */
1157 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1158 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1159 return NT_STATUS_CANNOT_DELETE;
1162 /* check the security descriptor */
1163 status = pvfs_access_check(pvfs, req, name, &access_mask);
1164 if (!NT_STATUS_IS_OK(status)) {
1168 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1169 NT_STATUS_NOT_OK_RETURN(status);
1171 f = talloc(h, struct pvfs_file);
1173 return NT_STATUS_NO_MEMORY;
1176 f->handle = talloc(f, struct pvfs_file_handle);
1177 if (f->handle == NULL) {
1178 return NT_STATUS_NO_MEMORY;
1183 f->pending_list = NULL;
1185 f->share_access = io->generic.in.share_access;
1186 f->access_mask = access_mask;
1187 f->impersonation = io->generic.in.impersonation;
1188 f->notify_buffer = NULL;
1191 f->handle->pvfs = pvfs;
1193 f->handle->name = talloc_steal(f->handle, name);
1194 f->handle->create_options = io->generic.in.create_options;
1195 f->handle->seek_offset = 0;
1196 f->handle->position = 0;
1197 f->handle->mode = 0;
1198 f->handle->oplock = NULL;
1199 f->handle->have_opendb_entry = false;
1200 f->handle->sticky_write_time = false;
1201 f->handle->open_completed = false;
1203 /* form the lock context used for byte range locking and
1205 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1206 if (!NT_STATUS_IS_OK(status)) {
1210 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1211 if (!NT_STATUS_IS_OK(status)) {
1215 /* get a lock on this file before the actual open */
1216 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1218 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1220 /* we were supposed to do a blocking lock, so something
1222 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1225 DLIST_ADD(pvfs->files.list, f);
1227 /* setup a destructor to avoid file descriptor leaks on
1228 abnormal termination */
1229 talloc_set_destructor(f, pvfs_fnum_destructor);
1230 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1233 * Only SMB2 takes care of the delete_on_close,
1236 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1237 req->ctx->protocol == PROTOCOL_SMB2) {
1238 del_on_close = true;
1240 del_on_close = false;
1243 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1244 oplock_level = OPLOCK_NONE;
1245 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1246 oplock_level = OPLOCK_BATCH;
1247 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1248 oplock_level = OPLOCK_EXCLUSIVE;
1251 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1252 allow_level_II_oplock = true;
1255 /* see if we are allowed to open at the same time as existing opens */
1256 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
1257 share_access, access_mask, del_on_close,
1258 io->generic.in.open_disposition,
1259 false, allow_level_II_oplock,
1260 oplock_level, &oplock_granted);
1263 * on a sharing violation we need to retry when the file is closed by
1264 * the other user, or after 1 second
1265 * on a non granted oplock we need to retry when the file is closed by
1266 * the other user, or after 30 seconds
1268 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1269 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1270 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1271 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1274 if (!NT_STATUS_IS_OK(status)) {
1279 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1280 oplock_granted = OPLOCK_BATCH;
1281 } else if (oplock_granted != OPLOCK_NONE) {
1282 status = pvfs_setup_oplock(f, oplock_granted);
1283 if (!NT_STATUS_IS_OK(status)) {
1289 f->handle->have_opendb_entry = true;
1291 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1297 /* do the actual open */
1298 fd = open(f->handle->name->full_name, flags);
1301 return pvfs_map_errno(f->pvfs, errno);
1306 stream_existed = name->stream_exists;
1308 /* if this was a stream create then create the stream as well */
1309 if (!name->stream_exists) {
1310 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1311 if (!NT_STATUS_IS_OK(status)) {
1315 if (stream_truncate) {
1316 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1317 if (!NT_STATUS_IS_OK(status)) {
1324 /* re-resolve the open fd */
1325 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1326 if (!NT_STATUS_IS_OK(status)) {
1331 if (f->handle->name->stream_id == 0 &&
1332 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1333 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1334 /* for overwrite we need to replace file permissions */
1335 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1336 mode_t mode = pvfs_fileperms(pvfs, attrib);
1337 if (fchmod(fd, mode) == -1) {
1339 return pvfs_map_errno(pvfs, errno);
1341 name->dos.attrib = attrib;
1342 status = pvfs_dosattrib_save(pvfs, name, fd);
1343 if (!NT_STATUS_IS_OK(status)) {
1351 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1352 NT_STATUS_NOT_OK_RETURN(status);
1354 /* mark the open as having completed fully, so delete on close
1356 f->handle->open_completed = true;
1358 io->generic.out.oplock_level = oplock_granted;
1359 io->generic.out.file.ntvfs = h;
1360 io->generic.out.create_action = stream_existed?
1361 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1362 io->generic.out.create_time = name->dos.create_time;
1363 io->generic.out.access_time = name->dos.access_time;
1364 io->generic.out.write_time = name->dos.write_time;
1365 io->generic.out.change_time = name->dos.change_time;
1366 io->generic.out.attrib = name->dos.attrib;
1367 io->generic.out.alloc_size = name->dos.alloc_size;
1368 io->generic.out.size = name->st.st_size;
1369 io->generic.out.file_type = FILE_TYPE_DISK;
1370 io->generic.out.ipc_state = 0;
1371 io->generic.out.is_directory = 0;
1373 return NT_STATUS_OK;
1380 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1381 struct ntvfs_request *req, union smb_close *io)
1383 struct pvfs_state *pvfs = ntvfs->private_data;
1384 struct pvfs_file *f;
1385 struct utimbuf unix_times;
1387 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1388 return NT_STATUS_DOS(ERRSRV, ERRerror);
1391 if (io->generic.level != RAW_CLOSE_CLOSE) {
1392 return ntvfs_map_close(ntvfs, req, io);
1395 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1397 return NT_STATUS_INVALID_HANDLE;
1400 if (!null_time(io->close.in.write_time)) {
1401 unix_times.actime = 0;
1402 unix_times.modtime = io->close.in.write_time;
1403 utime(f->handle->name->full_name, &unix_times);
1404 } else if (f->handle->sticky_write_time) {
1405 unix_times.actime = 0;
1406 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1407 utime(f->handle->name->full_name, &unix_times);
1412 return NT_STATUS_OK;
1417 logoff - close all file descriptors open by a vuid
1419 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1420 struct ntvfs_request *req)
1422 struct pvfs_state *pvfs = ntvfs->private_data;
1423 struct pvfs_file *f, *next;
1425 for (f=pvfs->files.list;f;f=next) {
1427 if (f->ntvfs->session_info == req->session_info) {
1432 return NT_STATUS_OK;
1437 exit - close files for the current pid
1439 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1440 struct ntvfs_request *req)
1442 struct pvfs_state *pvfs = ntvfs->private_data;
1443 struct pvfs_file *f, *next;
1445 for (f=pvfs->files.list;f;f=next) {
1447 if (f->ntvfs->session_info == req->session_info &&
1448 f->ntvfs->smbpid == req->smbpid) {
1453 return NT_STATUS_OK;
1458 change the delete on close flag on an already open file
1460 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1461 struct ntvfs_request *req,
1462 struct pvfs_file *f, bool del_on_close)
1464 struct odb_lock *lck;
1467 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1468 return NT_STATUS_CANNOT_DELETE;
1471 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1472 !pvfs_directory_empty(pvfs, f->handle->name)) {
1473 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1477 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1479 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1482 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1484 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1487 status = odb_set_delete_on_close(lck, del_on_close);
1496 determine if a file can be deleted, or if it is prevented by an
1499 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1500 struct ntvfs_request *req,
1501 struct pvfs_filename *name,
1502 struct odb_lock **lckp)
1506 struct odb_lock *lck;
1507 uint32_t share_access;
1508 uint32_t access_mask;
1509 bool delete_on_close;
1511 status = pvfs_locking_key(name, name, &key);
1512 if (!NT_STATUS_IS_OK(status)) {
1513 return NT_STATUS_NO_MEMORY;
1516 lck = odb_lock(req, pvfs->odb_context, &key);
1518 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1519 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1522 share_access = NTCREATEX_SHARE_ACCESS_READ |
1523 NTCREATEX_SHARE_ACCESS_WRITE |
1524 NTCREATEX_SHARE_ACCESS_DELETE;
1525 access_mask = SEC_STD_DELETE;
1526 delete_on_close = true;
1528 status = odb_can_open(lck, name->stream_id,
1529 share_access, access_mask, delete_on_close,
1530 NTCREATEX_DISP_OPEN, false);
1532 if (NT_STATUS_IS_OK(status)) {
1533 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1537 * if it's a sharing violation or we got no oplock
1538 * only keep the lock if the caller requested access
1541 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1542 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1548 } else if (!NT_STATUS_IS_OK(status)) {
1561 determine if a file can be renamed, or if it is prevented by an
1564 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1565 struct ntvfs_request *req,
1566 struct pvfs_filename *name,
1567 struct odb_lock **lckp)
1571 struct odb_lock *lck;
1572 uint32_t share_access;
1573 uint32_t access_mask;
1574 bool delete_on_close;
1576 status = pvfs_locking_key(name, name, &key);
1577 if (!NT_STATUS_IS_OK(status)) {
1578 return NT_STATUS_NO_MEMORY;
1581 lck = odb_lock(req, pvfs->odb_context, &key);
1583 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1584 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1587 share_access = NTCREATEX_SHARE_ACCESS_READ |
1588 NTCREATEX_SHARE_ACCESS_WRITE;
1589 access_mask = SEC_STD_DELETE;
1590 delete_on_close = false;
1592 status = odb_can_open(lck, name->stream_id,
1593 share_access, access_mask, delete_on_close,
1594 NTCREATEX_DISP_OPEN, false);
1597 * if it's a sharing violation or we got no oplock
1598 * only keep the lock if the caller requested access
1601 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1602 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1608 } else if (!NT_STATUS_IS_OK(status)) {
1621 determine if the file size of a file can be changed,
1622 or if it is prevented by an already open file
1624 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1625 struct ntvfs_request *req,
1626 struct pvfs_filename *name,
1627 struct odb_lock **lckp)
1631 struct odb_lock *lck;
1632 uint32_t share_access;
1633 uint32_t access_mask;
1635 bool delete_on_close;
1637 status = pvfs_locking_key(name, name, &key);
1638 if (!NT_STATUS_IS_OK(status)) {
1639 return NT_STATUS_NO_MEMORY;
1642 lck = odb_lock(req, pvfs->odb_context, &key);
1644 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1645 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1648 share_access = NTCREATEX_SHARE_ACCESS_READ |
1649 NTCREATEX_SHARE_ACCESS_WRITE |
1650 NTCREATEX_SHARE_ACCESS_DELETE;
1652 * I would have thought that we would need to pass
1653 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1655 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1656 * to set the filesize.
1660 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1661 delete_on_close = false;
1662 break_to_none = true;
1664 status = odb_can_open(lck, name->stream_id,
1665 share_access, access_mask, delete_on_close,
1666 NTCREATEX_DISP_OPEN, break_to_none);
1669 * if it's a sharing violation or we got no oplock
1670 * only keep the lock if the caller requested access
1673 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1674 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1680 } else if (!NT_STATUS_IS_OK(status)) {
1693 determine if file meta data can be accessed, or if it is prevented by an
1696 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1697 struct ntvfs_request *req,
1698 struct pvfs_filename *name)
1702 struct odb_lock *lck;
1703 uint32_t share_access;
1704 uint32_t access_mask;
1705 bool delete_on_close;
1707 status = pvfs_locking_key(name, name, &key);
1708 if (!NT_STATUS_IS_OK(status)) {
1709 return NT_STATUS_NO_MEMORY;
1712 lck = odb_lock(req, pvfs->odb_context, &key);
1714 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1715 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1718 share_access = NTCREATEX_SHARE_ACCESS_READ |
1719 NTCREATEX_SHARE_ACCESS_WRITE;
1720 access_mask = SEC_FILE_READ_ATTRIBUTE;
1721 delete_on_close = false;
1723 status = odb_can_open(lck, name->stream_id,
1724 share_access, access_mask, delete_on_close,
1725 NTCREATEX_DISP_OPEN, false);
1727 if (!NT_STATUS_IS_OK(status)) {
1736 determine if delete on close is set on
1738 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1743 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1745 if (!NT_STATUS_IS_OK(status)) {
1746 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1750 return del_on_close;