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,
303 NULL, false, OPLOCK_NONE, NULL);
305 if (!NT_STATUS_IS_OK(status)) {
310 f->handle->have_opendb_entry = true;
313 DLIST_ADD(pvfs->files.list, f);
315 /* setup destructors to avoid leaks on abnormal termination */
316 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
317 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
320 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
321 mode_t mode = pvfs_fileperms(pvfs, attrib);
323 if (mkdir(name->full_name, mode) == -1) {
324 return pvfs_map_errno(pvfs,errno);
327 pvfs_xattr_unlink_hook(pvfs, name->full_name);
329 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
330 if (!NT_STATUS_IS_OK(status)) {
334 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
335 if (!NT_STATUS_IS_OK(status)) {
339 /* form the lock context used for opendb locking */
340 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
341 if (!NT_STATUS_IS_OK(status)) {
345 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
347 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
349 /* we were supposed to do a blocking lock, so something
351 return NT_STATUS_INTERNAL_DB_CORRUPTION;
354 status = odb_can_open(lck, name->stream_id,
355 share_access, access_mask, del_on_close,
356 io->generic.in.open_disposition, false);
358 if (!NT_STATUS_IS_OK(status)) {
362 status = odb_open_file(lck, f->handle, name->full_name,
363 NULL, false, OPLOCK_NONE, NULL);
365 if (!NT_STATUS_IS_OK(status)) {
369 f->handle->have_opendb_entry = true;
371 create_action = NTCREATEX_ACTION_CREATED;
373 notify_trigger(pvfs->notify_context,
375 FILE_NOTIFY_CHANGE_DIR_NAME,
378 create_action = NTCREATEX_ACTION_EXISTED;
382 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
385 /* the open succeeded, keep this handle permanently */
386 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
387 if (!NT_STATUS_IS_OK(status)) {
391 f->handle->open_completed = true;
393 io->generic.out.oplock_level = OPLOCK_NONE;
394 io->generic.out.file.ntvfs = h;
395 io->generic.out.create_action = create_action;
396 io->generic.out.create_time = name->dos.create_time;
397 io->generic.out.access_time = name->dos.access_time;
398 io->generic.out.write_time = name->dos.write_time;
399 io->generic.out.change_time = name->dos.change_time;
400 io->generic.out.attrib = name->dos.attrib;
401 io->generic.out.alloc_size = name->dos.alloc_size;
402 io->generic.out.size = name->st.st_size;
403 io->generic.out.file_type = FILE_TYPE_DISK;
404 io->generic.out.ipc_state = 0;
405 io->generic.out.is_directory = 1;
410 rmdir(name->full_name);
415 destroy a struct pvfs_file_handle
417 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
419 /* the write time is no longer sticky */
420 if (h->sticky_write_time) {
422 status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
423 if (NT_STATUS_IS_OK(status)) {
424 h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
425 pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
429 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
430 h->name->stream_name) {
432 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
433 if (!NT_STATUS_IS_OK(status)) {
434 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
435 h->name->stream_name, h->name->full_name));
440 if (close(h->fd) != 0) {
441 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
442 h->fd, h->name->full_name, strerror(errno)));
447 if (h->have_opendb_entry) {
448 struct odb_lock *lck;
450 const char *delete_path = NULL;
452 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
454 DEBUG(0,("Unable to lock opendb for close\n"));
458 status = odb_close_file(lck, h, &delete_path);
459 if (!NT_STATUS_IS_OK(status)) {
460 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
461 h->name->full_name, nt_errstr(status)));
464 if (h->name->stream_name == NULL &&
465 h->open_completed && delete_path) {
466 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
467 if (!NT_STATUS_IS_OK(status)) {
468 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
469 delete_path, nt_errstr(status)));
471 if (unlink(delete_path) != 0) {
472 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
473 delete_path, strerror(errno)));
475 notify_trigger(h->pvfs->notify_context,
476 NOTIFY_ACTION_REMOVED,
477 FILE_NOTIFY_CHANGE_FILE_NAME,
490 destroy a struct pvfs_file
492 static int pvfs_fnum_destructor(struct pvfs_file *f)
494 DLIST_REMOVE(f->pvfs->files.list, f);
495 pvfs_lock_close(f->pvfs, f);
496 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
503 form the lock context used for byte range locking. This is separate
504 from the locking key used for opendb locking as it needs to take
505 account of file streams (each stream is a separate byte range
508 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
509 struct pvfs_filename *name,
510 struct ntvfs_handle *ntvfs,
511 struct brl_handle **_h)
513 DATA_BLOB odb_key, key;
515 struct brl_handle *h;
517 status = pvfs_locking_key(name, mem_ctx, &odb_key);
518 NT_STATUS_NOT_OK_RETURN(status);
520 if (name->stream_name == NULL) {
523 key = data_blob_talloc(mem_ctx, NULL,
524 odb_key.length + strlen(name->stream_name) + 1);
525 NT_STATUS_HAVE_NO_MEMORY(key.data);
526 memcpy(key.data, odb_key.data, odb_key.length);
527 memcpy(key.data + odb_key.length,
528 name->stream_name, strlen(name->stream_name) + 1);
529 data_blob_free(&odb_key);
532 h = brl_create_handle(mem_ctx, ntvfs, &key);
533 NT_STATUS_HAVE_NO_MEMORY(h);
542 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
543 struct ntvfs_request *req,
544 struct pvfs_filename *name,
549 struct ntvfs_handle *h;
551 struct odb_lock *lck;
552 uint32_t create_options = io->generic.in.create_options;
553 uint32_t share_access = io->generic.in.share_access;
554 uint32_t access_mask = io->generic.in.access_mask;
558 struct pvfs_filename *parent;
559 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
560 bool allow_level_II_oplock = false;
562 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
563 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
564 return NT_STATUS_CANNOT_DELETE;
567 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
568 NT_STATUS_NOT_OK_RETURN(status);
570 /* check that the parent isn't opened with delete on close set */
571 status = pvfs_resolve_parent(pvfs, req, name, &parent);
572 if (NT_STATUS_IS_OK(status)) {
573 DATA_BLOB locking_key;
574 status = pvfs_locking_key(parent, req, &locking_key);
575 NT_STATUS_NOT_OK_RETURN(status);
576 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key,
578 NT_STATUS_NOT_OK_RETURN(status);
580 return NT_STATUS_DELETE_PENDING;
584 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
590 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
591 NT_STATUS_NOT_OK_RETURN(status);
593 f = talloc(h, struct pvfs_file);
594 NT_STATUS_HAVE_NO_MEMORY(f);
596 f->handle = talloc(f, struct pvfs_file_handle);
597 NT_STATUS_HAVE_NO_MEMORY(f->handle);
599 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
600 mode = pvfs_fileperms(pvfs, attrib);
602 /* create the file */
603 fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
605 return pvfs_map_errno(pvfs, errno);
608 pvfs_xattr_unlink_hook(pvfs, name->full_name);
610 /* if this was a stream create then create the stream as well */
611 if (name->stream_name) {
612 status = pvfs_stream_create(pvfs, name, fd);
613 if (!NT_STATUS_IS_OK(status)) {
619 /* re-resolve the open fd */
620 status = pvfs_resolve_name_fd(pvfs, fd, name);
621 if (!NT_STATUS_IS_OK(status)) {
626 name->dos.attrib = attrib;
627 status = pvfs_dosattrib_save(pvfs, name, fd);
628 if (!NT_STATUS_IS_OK(status)) {
633 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
634 if (!NT_STATUS_IS_OK(status)) {
638 /* form the lock context used for byte range locking and
640 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
641 if (!NT_STATUS_IS_OK(status)) {
645 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
646 if (!NT_STATUS_IS_OK(status)) {
650 /* grab a lock on the open file record */
651 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
653 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
655 /* we were supposed to do a blocking lock, so something
657 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
661 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
664 del_on_close = false;
667 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
668 oplock_level = OPLOCK_NONE;
669 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
670 oplock_level = OPLOCK_BATCH;
671 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
672 oplock_level = OPLOCK_EXCLUSIVE;
675 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
676 allow_level_II_oplock = true;
679 status = odb_can_open(lck, name->stream_id,
680 share_access, access_mask, del_on_close,
681 io->generic.in.open_disposition, false);
682 if (!NT_STATUS_IS_OK(status)) {
684 /* bad news, we must have hit a race - we don't delete the file
685 here as the most likely scenario is that someone else created
686 the file at the same time */
693 f->pending_list = NULL;
695 f->share_access = io->generic.in.share_access;
696 f->access_mask = access_mask;
697 f->impersonation = io->generic.in.impersonation;
698 f->notify_buffer = NULL;
701 f->handle->pvfs = pvfs;
702 f->handle->name = talloc_steal(f->handle, name);
704 f->handle->create_options = io->generic.in.create_options;
705 f->handle->seek_offset = 0;
706 f->handle->position = 0;
708 f->handle->oplock = NULL;
709 f->handle->have_opendb_entry = true;
710 f->handle->sticky_write_time = false;
711 f->handle->open_completed = false;
713 status = odb_open_file(lck, f->handle, name->full_name,
714 &f->handle->fd, allow_level_II_oplock,
715 oplock_level, &oplock_granted);
717 if (!NT_STATUS_IS_OK(status)) {
718 /* bad news, we must have hit a race - we don't delete the file
719 here as the most likely scenario is that someone else created
720 the file at the same time */
725 DLIST_ADD(pvfs->files.list, f);
727 /* setup a destructor to avoid file descriptor leaks on
728 abnormal termination */
729 talloc_set_destructor(f, pvfs_fnum_destructor);
730 talloc_set_destructor(f->handle, pvfs_handle_destructor);
732 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
733 oplock_granted = OPLOCK_BATCH;
734 } else if (oplock_granted != OPLOCK_NONE) {
735 status = pvfs_setup_oplock(f, oplock_granted);
736 if (!NT_STATUS_IS_OK(status)) {
741 io->generic.out.oplock_level = oplock_granted;
742 io->generic.out.file.ntvfs = f->ntvfs;
743 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
744 io->generic.out.create_time = name->dos.create_time;
745 io->generic.out.access_time = name->dos.access_time;
746 io->generic.out.write_time = name->dos.write_time;
747 io->generic.out.change_time = name->dos.change_time;
748 io->generic.out.attrib = name->dos.attrib;
749 io->generic.out.alloc_size = name->dos.alloc_size;
750 io->generic.out.size = name->st.st_size;
751 io->generic.out.file_type = FILE_TYPE_DISK;
752 io->generic.out.ipc_state = 0;
753 io->generic.out.is_directory = 0;
755 /* success - keep the file handle */
756 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
757 if (!NT_STATUS_IS_OK(status)) {
761 f->handle->open_completed = true;
763 notify_trigger(pvfs->notify_context,
765 FILE_NOTIFY_CHANGE_FILE_NAME,
772 unlink(name->full_name);
777 state of a pending retry
779 struct pvfs_odb_retry {
780 struct ntvfs_module_context *ntvfs;
781 struct ntvfs_request *req;
782 DATA_BLOB odb_locking_key;
785 void (*callback)(struct pvfs_odb_retry *r,
786 struct ntvfs_module_context *ntvfs,
787 struct ntvfs_request *req,
790 enum pvfs_wait_notice reason);
793 /* destroy a pending request */
794 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
796 struct pvfs_state *pvfs = r->ntvfs->private_data;
797 if (r->odb_locking_key.data) {
798 struct odb_lock *lck;
799 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
801 odb_remove_pending(lck, r);
808 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
810 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
812 if (reason == PVFS_WAIT_EVENT) {
814 * The pending odb entry is already removed.
815 * We use a null locking key to indicate this
818 data_blob_free(&r->odb_locking_key);
821 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
825 setup for a retry of a request that was rejected
828 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
829 struct ntvfs_request *req,
830 struct odb_lock *lck,
831 struct timeval end_time,
834 void (*callback)(struct pvfs_odb_retry *r,
835 struct ntvfs_module_context *ntvfs,
836 struct ntvfs_request *req,
839 enum pvfs_wait_notice reason))
841 struct pvfs_state *pvfs = ntvfs->private_data;
842 struct pvfs_odb_retry *r;
843 struct pvfs_wait *wait_handle;
846 r = talloc(req, struct pvfs_odb_retry);
847 NT_STATUS_HAVE_NO_MEMORY(r);
852 r->private_data = private_data;
853 r->callback = callback;
854 r->odb_locking_key = odb_get_key(r, lck);
855 if (r->odb_locking_key.data == NULL) {
856 return NT_STATUS_NO_MEMORY;
859 /* setup a pending lock */
860 status = odb_open_file_pending(lck, r);
861 if (!NT_STATUS_IS_OK(status)) {
867 talloc_set_destructor(r, pvfs_odb_retry_destructor);
869 wait_handle = pvfs_wait_message(pvfs, req,
870 MSG_PVFS_RETRY_OPEN, end_time,
871 pvfs_odb_retry_callback, r);
872 if (wait_handle == NULL) {
873 return NT_STATUS_NO_MEMORY;
876 talloc_steal(r, wait_handle);
878 talloc_steal(pvfs, r);
884 retry an open after a sharing violation
886 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
887 struct ntvfs_module_context *ntvfs,
888 struct ntvfs_request *req,
891 enum pvfs_wait_notice reason)
893 union smb_open *io = talloc_get_type(_io, union smb_open);
896 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
897 just a bug in their server, but we better do the same */
898 if (reason == PVFS_WAIT_CANCEL) {
902 if (reason == PVFS_WAIT_TIMEOUT) {
903 /* if it timed out, then give the failure
906 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
907 req->async_states->send_fn(req);
913 /* try the open again, which could trigger another retry setup
914 if it wants to, so we have to unmark the async flag so we
915 will know if it does a second async reply */
916 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
918 status = pvfs_open(ntvfs, req, io);
919 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
920 /* the 2nd try also replied async, so we don't send
925 /* re-mark it async, just in case someone up the chain does
927 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
929 /* send the reply up the chain */
930 req->async_states->status = status;
931 req->async_states->send_fn(req);
936 special handling for openx DENY_DOS semantics
938 This function attempts a reference open using an existing handle. If its allowed,
939 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
940 open processing continues.
942 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
943 struct ntvfs_request *req, union smb_open *io,
944 struct pvfs_file *f, struct odb_lock *lck)
946 struct pvfs_state *pvfs = ntvfs->private_data;
947 struct pvfs_file *f2;
948 struct pvfs_filename *name;
951 /* search for an existing open with the right parameters. Note
952 the magic ntcreatex options flag, which is set in the
953 generic mapping code. This might look ugly, but its
954 actually pretty much now w2k does it internally as well.
956 If you look at the BASE-DENYDOS test you will see that a
957 DENY_DOS is a very special case, and in the right
958 circumstances you actually get the _same_ handle back
959 twice, rather than a new handle.
961 for (f2=pvfs->files.list;f2;f2=f2->next) {
963 f2->ntvfs->session_info == req->session_info &&
964 f2->ntvfs->smbpid == req->smbpid &&
965 (f2->handle->create_options &
966 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
967 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
968 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
969 strcasecmp_m(f2->handle->name->original_name,
970 io->generic.in.fname)==0) {
976 return NT_STATUS_SHARING_VIOLATION;
979 /* quite an insane set of semantics ... */
980 if (is_exe_filename(io->generic.in.fname) &&
981 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
982 return NT_STATUS_SHARING_VIOLATION;
986 setup a reference to the existing handle
988 talloc_free(f->handle);
989 f->handle = talloc_reference(f, f2->handle);
993 name = f->handle->name;
995 io->generic.out.oplock_level = OPLOCK_NONE;
996 io->generic.out.file.ntvfs = f->ntvfs;
997 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
998 io->generic.out.create_time = name->dos.create_time;
999 io->generic.out.access_time = name->dos.access_time;
1000 io->generic.out.write_time = name->dos.write_time;
1001 io->generic.out.change_time = name->dos.change_time;
1002 io->generic.out.attrib = name->dos.attrib;
1003 io->generic.out.alloc_size = name->dos.alloc_size;
1004 io->generic.out.size = name->st.st_size;
1005 io->generic.out.file_type = FILE_TYPE_DISK;
1006 io->generic.out.ipc_state = 0;
1007 io->generic.out.is_directory = 0;
1009 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1010 NT_STATUS_NOT_OK_RETURN(status);
1012 return NT_STATUS_OK;
1018 setup for a open retry after a sharing violation
1020 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1021 struct ntvfs_request *req,
1023 struct pvfs_file *f,
1024 struct odb_lock *lck,
1025 NTSTATUS parent_status)
1027 struct pvfs_state *pvfs = ntvfs->private_data;
1029 struct timeval end_time;
1031 if (io->generic.in.create_options &
1032 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1033 /* see if we can satisfy the request using the special DENY_DOS
1035 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1036 if (NT_STATUS_IS_OK(status)) {
1041 /* the retry should allocate a new file handle */
1044 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1045 end_time = timeval_add(&req->statistics.request_time,
1046 0, pvfs->sharing_violation_delay);
1047 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1048 end_time = timeval_add(&req->statistics.request_time,
1049 pvfs->oplock_break_timeout, 0);
1051 return NT_STATUS_INTERNAL_ERROR;
1054 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
1055 pvfs_retry_open_sharing);
1061 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1062 struct ntvfs_request *req, union smb_open *io)
1064 struct pvfs_state *pvfs = ntvfs->private_data;
1066 struct pvfs_filename *name;
1067 struct pvfs_file *f;
1068 struct ntvfs_handle *h;
1071 struct odb_lock *lck;
1072 uint32_t create_options;
1073 uint32_t share_access;
1074 uint32_t access_mask;
1076 bool stream_existed, stream_truncate=false;
1077 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1078 bool allow_level_II_oplock = false;
1080 /* use the generic mapping code to avoid implementing all the
1081 different open calls. */
1082 if (io->generic.level != RAW_OPEN_GENERIC &&
1083 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1084 return ntvfs_map_open(ntvfs, req, io);
1087 /* resolve the cifs name to a posix name */
1088 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1089 PVFS_RESOLVE_STREAMS, &name);
1090 if (!NT_STATUS_IS_OK(status)) {
1094 /* directory opens are handled separately */
1095 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1096 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1097 return pvfs_open_directory(pvfs, req, name, io);
1100 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1101 open doesn't match */
1102 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1104 create_options = io->generic.in.create_options;
1105 share_access = io->generic.in.share_access;
1106 access_mask = io->generic.in.access_mask;
1108 /* certain create options are not allowed */
1109 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1110 !(access_mask & SEC_STD_DELETE)) {
1111 return NT_STATUS_INVALID_PARAMETER;
1116 switch (io->generic.in.open_disposition) {
1117 case NTCREATEX_DISP_SUPERSEDE:
1118 case NTCREATEX_DISP_OVERWRITE_IF:
1119 if (name->stream_name == NULL) {
1122 stream_truncate = true;
1126 case NTCREATEX_DISP_OPEN:
1127 if (!name->stream_exists) {
1128 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1133 case NTCREATEX_DISP_OVERWRITE:
1134 if (!name->stream_exists) {
1135 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1137 if (name->stream_name == NULL) {
1140 stream_truncate = true;
1144 case NTCREATEX_DISP_CREATE:
1145 if (name->stream_exists) {
1146 return NT_STATUS_OBJECT_NAME_COLLISION;
1151 case NTCREATEX_DISP_OPEN_IF:
1156 return NT_STATUS_INVALID_PARAMETER;
1159 /* handle creating a new file separately */
1160 if (!name->exists) {
1161 status = pvfs_create_file(pvfs, req, name, io);
1162 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1166 /* we've hit a race - the file was created during this call */
1167 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1171 /* try re-resolving the name */
1172 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1173 if (!NT_STATUS_IS_OK(status)) {
1176 /* fall through to a normal open */
1179 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1180 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1181 return NT_STATUS_CANNOT_DELETE;
1184 /* check the security descriptor */
1185 status = pvfs_access_check(pvfs, req, name, &access_mask);
1186 if (!NT_STATUS_IS_OK(status)) {
1190 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1191 NT_STATUS_NOT_OK_RETURN(status);
1193 f = talloc(h, struct pvfs_file);
1195 return NT_STATUS_NO_MEMORY;
1198 f->handle = talloc(f, struct pvfs_file_handle);
1199 if (f->handle == NULL) {
1200 return NT_STATUS_NO_MEMORY;
1205 f->pending_list = NULL;
1207 f->share_access = io->generic.in.share_access;
1208 f->access_mask = access_mask;
1209 f->impersonation = io->generic.in.impersonation;
1210 f->notify_buffer = NULL;
1213 f->handle->pvfs = pvfs;
1215 f->handle->name = talloc_steal(f->handle, name);
1216 f->handle->create_options = io->generic.in.create_options;
1217 f->handle->seek_offset = 0;
1218 f->handle->position = 0;
1219 f->handle->mode = 0;
1220 f->handle->oplock = NULL;
1221 f->handle->have_opendb_entry = false;
1222 f->handle->sticky_write_time = false;
1223 f->handle->open_completed = false;
1225 /* form the lock context used for byte range locking and
1227 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1228 if (!NT_STATUS_IS_OK(status)) {
1232 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1233 if (!NT_STATUS_IS_OK(status)) {
1237 /* get a lock on this file before the actual open */
1238 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1240 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1242 /* we were supposed to do a blocking lock, so something
1244 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1247 DLIST_ADD(pvfs->files.list, f);
1249 /* setup a destructor to avoid file descriptor leaks on
1250 abnormal termination */
1251 talloc_set_destructor(f, pvfs_fnum_destructor);
1252 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1255 * Only SMB2 takes care of the delete_on_close,
1258 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1259 req->ctx->protocol == PROTOCOL_SMB2) {
1260 del_on_close = true;
1262 del_on_close = false;
1265 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1266 oplock_level = OPLOCK_NONE;
1267 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1268 oplock_level = OPLOCK_BATCH;
1269 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1270 oplock_level = OPLOCK_EXCLUSIVE;
1273 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1274 allow_level_II_oplock = true;
1277 /* see if we are allowed to open at the same time as existing opens */
1278 status = odb_can_open(lck, name->stream_id,
1279 share_access, access_mask, del_on_close,
1280 io->generic.in.open_disposition, false);
1283 * on a sharing violation we need to retry when the file is closed by
1284 * the other user, or after 1 second
1285 * on a non granted oplock we need to retry when the file is closed by
1286 * the other user, or after 30 seconds
1288 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1289 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1290 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1291 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1294 if (!NT_STATUS_IS_OK(status)) {
1299 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1305 /* do the actual open */
1306 fd = open(f->handle->name->full_name, flags);
1309 return pvfs_map_errno(f->pvfs, errno);
1314 /* now really mark the file as open */
1315 status = odb_open_file(lck, f->handle, name->full_name,
1316 &f->handle->fd, allow_level_II_oplock,
1317 oplock_level, &oplock_granted);
1319 if (!NT_STATUS_IS_OK(status)) {
1324 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1325 oplock_granted = OPLOCK_BATCH;
1326 } else if (oplock_granted != OPLOCK_NONE) {
1327 status = pvfs_setup_oplock(f, oplock_granted);
1328 if (!NT_STATUS_IS_OK(status)) {
1334 f->handle->have_opendb_entry = true;
1336 stream_existed = name->stream_exists;
1338 /* if this was a stream create then create the stream as well */
1339 if (!name->stream_exists) {
1340 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1341 if (!NT_STATUS_IS_OK(status)) {
1345 if (stream_truncate) {
1346 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1347 if (!NT_STATUS_IS_OK(status)) {
1354 /* re-resolve the open fd */
1355 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1356 if (!NT_STATUS_IS_OK(status)) {
1361 if (f->handle->name->stream_id == 0 &&
1362 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1363 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1364 /* for overwrite we need to replace file permissions */
1365 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1366 mode_t mode = pvfs_fileperms(pvfs, attrib);
1367 if (fchmod(fd, mode) == -1) {
1369 return pvfs_map_errno(pvfs, errno);
1371 name->dos.attrib = attrib;
1372 status = pvfs_dosattrib_save(pvfs, name, fd);
1373 if (!NT_STATUS_IS_OK(status)) {
1381 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1382 NT_STATUS_NOT_OK_RETURN(status);
1384 /* mark the open as having completed fully, so delete on close
1386 f->handle->open_completed = true;
1388 io->generic.out.oplock_level = oplock_granted;
1389 io->generic.out.file.ntvfs = h;
1390 io->generic.out.create_action = stream_existed?
1391 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1392 io->generic.out.create_time = name->dos.create_time;
1393 io->generic.out.access_time = name->dos.access_time;
1394 io->generic.out.write_time = name->dos.write_time;
1395 io->generic.out.change_time = name->dos.change_time;
1396 io->generic.out.attrib = name->dos.attrib;
1397 io->generic.out.alloc_size = name->dos.alloc_size;
1398 io->generic.out.size = name->st.st_size;
1399 io->generic.out.file_type = FILE_TYPE_DISK;
1400 io->generic.out.ipc_state = 0;
1401 io->generic.out.is_directory = 0;
1403 return NT_STATUS_OK;
1410 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1411 struct ntvfs_request *req, union smb_close *io)
1413 struct pvfs_state *pvfs = ntvfs->private_data;
1414 struct pvfs_file *f;
1415 struct utimbuf unix_times;
1417 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1418 return NT_STATUS_DOS(ERRSRV, ERRerror);
1421 if (io->generic.level != RAW_CLOSE_CLOSE) {
1422 return ntvfs_map_close(ntvfs, req, io);
1425 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1427 return NT_STATUS_INVALID_HANDLE;
1430 if (!null_time(io->close.in.write_time)) {
1431 unix_times.actime = 0;
1432 unix_times.modtime = io->close.in.write_time;
1433 utime(f->handle->name->full_name, &unix_times);
1434 } else if (f->handle->sticky_write_time) {
1435 unix_times.actime = 0;
1436 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1437 utime(f->handle->name->full_name, &unix_times);
1442 return NT_STATUS_OK;
1447 logoff - close all file descriptors open by a vuid
1449 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1450 struct ntvfs_request *req)
1452 struct pvfs_state *pvfs = ntvfs->private_data;
1453 struct pvfs_file *f, *next;
1455 for (f=pvfs->files.list;f;f=next) {
1457 if (f->ntvfs->session_info == req->session_info) {
1462 return NT_STATUS_OK;
1467 exit - close files for the current pid
1469 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1470 struct ntvfs_request *req)
1472 struct pvfs_state *pvfs = ntvfs->private_data;
1473 struct pvfs_file *f, *next;
1475 for (f=pvfs->files.list;f;f=next) {
1477 if (f->ntvfs->session_info == req->session_info &&
1478 f->ntvfs->smbpid == req->smbpid) {
1483 return NT_STATUS_OK;
1488 change the delete on close flag on an already open file
1490 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1491 struct ntvfs_request *req,
1492 struct pvfs_file *f, bool del_on_close)
1494 struct odb_lock *lck;
1497 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1498 return NT_STATUS_CANNOT_DELETE;
1501 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1502 !pvfs_directory_empty(pvfs, f->handle->name)) {
1503 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1507 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1509 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1512 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1514 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1517 status = odb_set_delete_on_close(lck, del_on_close);
1526 determine if a file can be deleted, or if it is prevented by an
1529 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1530 struct ntvfs_request *req,
1531 struct pvfs_filename *name,
1532 struct odb_lock **lckp)
1536 struct odb_lock *lck;
1537 uint32_t share_access;
1538 uint32_t access_mask;
1539 bool delete_on_close;
1541 status = pvfs_locking_key(name, name, &key);
1542 if (!NT_STATUS_IS_OK(status)) {
1543 return NT_STATUS_NO_MEMORY;
1546 lck = odb_lock(req, pvfs->odb_context, &key);
1548 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1549 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1552 share_access = NTCREATEX_SHARE_ACCESS_READ |
1553 NTCREATEX_SHARE_ACCESS_WRITE |
1554 NTCREATEX_SHARE_ACCESS_DELETE;
1555 access_mask = SEC_STD_DELETE;
1556 delete_on_close = true;
1558 status = odb_can_open(lck, name->stream_id,
1559 share_access, access_mask, delete_on_close,
1560 NTCREATEX_DISP_OPEN, false);
1562 if (NT_STATUS_IS_OK(status)) {
1563 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1567 * if it's a sharing violation or we got no oplock
1568 * only keep the lock if the caller requested access
1571 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1572 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1578 } else if (!NT_STATUS_IS_OK(status)) {
1591 determine if a file can be renamed, or if it is prevented by an
1594 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1595 struct ntvfs_request *req,
1596 struct pvfs_filename *name,
1597 struct odb_lock **lckp)
1601 struct odb_lock *lck;
1602 uint32_t share_access;
1603 uint32_t access_mask;
1604 bool delete_on_close;
1606 status = pvfs_locking_key(name, name, &key);
1607 if (!NT_STATUS_IS_OK(status)) {
1608 return NT_STATUS_NO_MEMORY;
1611 lck = odb_lock(req, pvfs->odb_context, &key);
1613 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1614 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1617 share_access = NTCREATEX_SHARE_ACCESS_READ |
1618 NTCREATEX_SHARE_ACCESS_WRITE;
1619 access_mask = SEC_STD_DELETE;
1620 delete_on_close = false;
1622 status = odb_can_open(lck, name->stream_id,
1623 share_access, access_mask, delete_on_close,
1624 NTCREATEX_DISP_OPEN, false);
1627 * if it's a sharing violation or we got no oplock
1628 * only keep the lock if the caller requested access
1631 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1632 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1638 } else if (!NT_STATUS_IS_OK(status)) {
1651 determine if the file size of a file can be changed,
1652 or if it is prevented by an already open file
1654 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1655 struct ntvfs_request *req,
1656 struct pvfs_filename *name,
1657 struct odb_lock **lckp)
1661 struct odb_lock *lck;
1662 uint32_t share_access;
1663 uint32_t access_mask;
1665 bool delete_on_close;
1667 status = pvfs_locking_key(name, name, &key);
1668 if (!NT_STATUS_IS_OK(status)) {
1669 return NT_STATUS_NO_MEMORY;
1672 lck = odb_lock(req, pvfs->odb_context, &key);
1674 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1675 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1678 share_access = NTCREATEX_SHARE_ACCESS_READ |
1679 NTCREATEX_SHARE_ACCESS_WRITE |
1680 NTCREATEX_SHARE_ACCESS_DELETE;
1682 * I would have thought that we would need to pass
1683 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1685 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1686 * to set the filesize.
1690 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1691 delete_on_close = false;
1692 break_to_none = true;
1694 status = odb_can_open(lck, name->stream_id,
1695 share_access, access_mask, delete_on_close,
1696 NTCREATEX_DISP_OPEN, break_to_none);
1699 * if it's a sharing violation or we got no oplock
1700 * only keep the lock if the caller requested access
1703 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1704 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1710 } else if (!NT_STATUS_IS_OK(status)) {
1723 determine if file meta data can be accessed, or if it is prevented by an
1726 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1727 struct ntvfs_request *req,
1728 struct pvfs_filename *name)
1732 struct odb_lock *lck;
1733 uint32_t share_access;
1734 uint32_t access_mask;
1735 bool delete_on_close;
1737 status = pvfs_locking_key(name, name, &key);
1738 if (!NT_STATUS_IS_OK(status)) {
1739 return NT_STATUS_NO_MEMORY;
1742 lck = odb_lock(req, pvfs->odb_context, &key);
1744 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1745 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1748 share_access = NTCREATEX_SHARE_ACCESS_READ |
1749 NTCREATEX_SHARE_ACCESS_WRITE;
1750 access_mask = SEC_FILE_READ_ATTRIBUTE;
1751 delete_on_close = false;
1753 status = odb_can_open(lck, name->stream_id,
1754 share_access, access_mask, delete_on_close,
1755 NTCREATEX_DISP_OPEN, false);
1757 if (!NT_STATUS_IS_OK(status)) {
1766 determine if delete on close is set on
1768 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1773 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1775 if (!NT_STATUS_IS_OK(status)) {
1776 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1780 return del_on_close;