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| O_NONBLOCK, 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_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
863 * maybe only a unix application
866 data_blob_free(&r->odb_locking_key);
867 } else if (!NT_STATUS_IS_OK(status)) {
873 talloc_set_destructor(r, pvfs_odb_retry_destructor);
875 wait_handle = pvfs_wait_message(pvfs, req,
876 MSG_PVFS_RETRY_OPEN, end_time,
877 pvfs_odb_retry_callback, r);
878 if (wait_handle == NULL) {
879 return NT_STATUS_NO_MEMORY;
882 talloc_steal(r, wait_handle);
884 talloc_steal(pvfs, r);
890 retry an open after a sharing violation
892 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
893 struct ntvfs_module_context *ntvfs,
894 struct ntvfs_request *req,
897 enum pvfs_wait_notice reason)
899 union smb_open *io = talloc_get_type(_io, union smb_open);
900 struct timeval *final_timeout = NULL;
904 final_timeout = talloc_get_type(private_data,
908 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
909 just a bug in their server, but we better do the same */
910 if (reason == PVFS_WAIT_CANCEL) {
914 if (reason == PVFS_WAIT_TIMEOUT) {
916 !timeval_expired(final_timeout)) {
918 * we need to retry periodictly
919 * after an EAGAIN as there's
920 * no way the kernel tell us
921 * an oplock is released.
925 /* if it timed out, then give the failure
928 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
929 req->async_states->send_fn(req);
936 /* try the open again, which could trigger another retry setup
937 if it wants to, so we have to unmark the async flag so we
938 will know if it does a second async reply */
939 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
941 status = pvfs_open(ntvfs, req, io);
942 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
943 /* the 2nd try also replied async, so we don't send
948 /* re-mark it async, just in case someone up the chain does
950 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
952 /* send the reply up the chain */
953 req->async_states->status = status;
954 req->async_states->send_fn(req);
959 special handling for openx DENY_DOS semantics
961 This function attempts a reference open using an existing handle. If its allowed,
962 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
963 open processing continues.
965 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
966 struct ntvfs_request *req, union smb_open *io,
967 struct pvfs_file *f, struct odb_lock *lck)
969 struct pvfs_state *pvfs = ntvfs->private_data;
970 struct pvfs_file *f2;
971 struct pvfs_filename *name;
974 /* search for an existing open with the right parameters. Note
975 the magic ntcreatex options flag, which is set in the
976 generic mapping code. This might look ugly, but its
977 actually pretty much now w2k does it internally as well.
979 If you look at the BASE-DENYDOS test you will see that a
980 DENY_DOS is a very special case, and in the right
981 circumstances you actually get the _same_ handle back
982 twice, rather than a new handle.
984 for (f2=pvfs->files.list;f2;f2=f2->next) {
986 f2->ntvfs->session_info == req->session_info &&
987 f2->ntvfs->smbpid == req->smbpid &&
988 (f2->handle->create_options &
989 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
990 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
991 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
992 strcasecmp_m(f2->handle->name->original_name,
993 io->generic.in.fname)==0) {
999 return NT_STATUS_SHARING_VIOLATION;
1002 /* quite an insane set of semantics ... */
1003 if (is_exe_filename(io->generic.in.fname) &&
1004 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1005 return NT_STATUS_SHARING_VIOLATION;
1009 setup a reference to the existing handle
1011 talloc_free(f->handle);
1012 f->handle = talloc_reference(f, f2->handle);
1016 name = f->handle->name;
1018 io->generic.out.oplock_level = OPLOCK_NONE;
1019 io->generic.out.file.ntvfs = f->ntvfs;
1020 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1021 io->generic.out.create_time = name->dos.create_time;
1022 io->generic.out.access_time = name->dos.access_time;
1023 io->generic.out.write_time = name->dos.write_time;
1024 io->generic.out.change_time = name->dos.change_time;
1025 io->generic.out.attrib = name->dos.attrib;
1026 io->generic.out.alloc_size = name->dos.alloc_size;
1027 io->generic.out.size = name->st.st_size;
1028 io->generic.out.file_type = FILE_TYPE_DISK;
1029 io->generic.out.ipc_state = 0;
1030 io->generic.out.is_directory = 0;
1032 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1033 NT_STATUS_NOT_OK_RETURN(status);
1035 return NT_STATUS_OK;
1041 setup for a open retry after a sharing violation
1043 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1044 struct ntvfs_request *req,
1046 struct pvfs_file *f,
1047 struct odb_lock *lck,
1048 NTSTATUS parent_status)
1050 struct pvfs_state *pvfs = ntvfs->private_data;
1052 struct timeval end_time;
1053 struct timeval *final_timeout = NULL;
1055 if (io->generic.in.create_options &
1056 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1057 /* see if we can satisfy the request using the special DENY_DOS
1059 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1060 if (NT_STATUS_IS_OK(status)) {
1065 /* the retry should allocate a new file handle */
1068 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1069 end_time = timeval_add(&req->statistics.request_time,
1070 0, pvfs->sharing_violation_delay);
1071 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1072 end_time = timeval_add(&req->statistics.request_time,
1073 pvfs->oplock_break_timeout, 0);
1074 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1076 * we got EAGAIN which means a unix application
1077 * has an oplock or share mode
1079 * we retry every 4/5 of the sharing violation delay
1080 * to see if the unix application
1081 * has released the oplock or share mode.
1083 final_timeout = talloc(req, struct timeval);
1084 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1085 *final_timeout = timeval_add(&req->statistics.request_time,
1086 pvfs->oplock_break_timeout,
1088 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1089 end_time = timeval_min(final_timeout, &end_time);
1091 return NT_STATUS_INTERNAL_ERROR;
1094 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1095 final_timeout, pvfs_retry_open_sharing);
1101 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1102 struct ntvfs_request *req, union smb_open *io)
1104 struct pvfs_state *pvfs = ntvfs->private_data;
1106 struct pvfs_filename *name;
1107 struct pvfs_file *f;
1108 struct ntvfs_handle *h;
1111 struct odb_lock *lck;
1112 uint32_t create_options;
1113 uint32_t share_access;
1114 uint32_t access_mask;
1116 bool stream_existed, stream_truncate=false;
1117 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1118 bool allow_level_II_oplock = false;
1120 /* use the generic mapping code to avoid implementing all the
1121 different open calls. */
1122 if (io->generic.level != RAW_OPEN_GENERIC &&
1123 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1124 return ntvfs_map_open(ntvfs, req, io);
1127 /* resolve the cifs name to a posix name */
1128 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1129 PVFS_RESOLVE_STREAMS, &name);
1130 if (!NT_STATUS_IS_OK(status)) {
1134 /* directory opens are handled separately */
1135 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1136 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1137 return pvfs_open_directory(pvfs, req, name, io);
1140 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1141 open doesn't match */
1142 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1144 create_options = io->generic.in.create_options;
1145 share_access = io->generic.in.share_access;
1146 access_mask = io->generic.in.access_mask;
1148 /* certain create options are not allowed */
1149 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1150 !(access_mask & SEC_STD_DELETE)) {
1151 return NT_STATUS_INVALID_PARAMETER;
1156 switch (io->generic.in.open_disposition) {
1157 case NTCREATEX_DISP_SUPERSEDE:
1158 case NTCREATEX_DISP_OVERWRITE_IF:
1159 if (name->stream_name == NULL) {
1162 stream_truncate = true;
1166 case NTCREATEX_DISP_OPEN:
1167 if (!name->stream_exists) {
1168 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1173 case NTCREATEX_DISP_OVERWRITE:
1174 if (!name->stream_exists) {
1175 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1177 if (name->stream_name == NULL) {
1180 stream_truncate = true;
1184 case NTCREATEX_DISP_CREATE:
1185 if (name->stream_exists) {
1186 return NT_STATUS_OBJECT_NAME_COLLISION;
1191 case NTCREATEX_DISP_OPEN_IF:
1196 return NT_STATUS_INVALID_PARAMETER;
1199 /* handle creating a new file separately */
1200 if (!name->exists) {
1201 status = pvfs_create_file(pvfs, req, name, io);
1202 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1206 /* we've hit a race - the file was created during this call */
1207 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1211 /* try re-resolving the name */
1212 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1213 if (!NT_STATUS_IS_OK(status)) {
1216 /* fall through to a normal open */
1219 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1220 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1221 return NT_STATUS_CANNOT_DELETE;
1224 /* check the security descriptor */
1225 status = pvfs_access_check(pvfs, req, name, &access_mask);
1226 if (!NT_STATUS_IS_OK(status)) {
1230 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1231 NT_STATUS_NOT_OK_RETURN(status);
1233 f = talloc(h, struct pvfs_file);
1235 return NT_STATUS_NO_MEMORY;
1238 f->handle = talloc(f, struct pvfs_file_handle);
1239 if (f->handle == NULL) {
1240 return NT_STATUS_NO_MEMORY;
1245 f->pending_list = NULL;
1247 f->share_access = io->generic.in.share_access;
1248 f->access_mask = access_mask;
1249 f->impersonation = io->generic.in.impersonation;
1250 f->notify_buffer = NULL;
1253 f->handle->pvfs = pvfs;
1255 f->handle->name = talloc_steal(f->handle, name);
1256 f->handle->create_options = io->generic.in.create_options;
1257 f->handle->seek_offset = 0;
1258 f->handle->position = 0;
1259 f->handle->mode = 0;
1260 f->handle->oplock = NULL;
1261 f->handle->have_opendb_entry = false;
1262 f->handle->sticky_write_time = false;
1263 f->handle->open_completed = false;
1265 /* form the lock context used for byte range locking and
1267 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1268 if (!NT_STATUS_IS_OK(status)) {
1272 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1273 if (!NT_STATUS_IS_OK(status)) {
1277 /* get a lock on this file before the actual open */
1278 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1280 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1282 /* we were supposed to do a blocking lock, so something
1284 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1287 DLIST_ADD(pvfs->files.list, f);
1289 /* setup a destructor to avoid file descriptor leaks on
1290 abnormal termination */
1291 talloc_set_destructor(f, pvfs_fnum_destructor);
1292 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1295 * Only SMB2 takes care of the delete_on_close,
1298 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1299 req->ctx->protocol == PROTOCOL_SMB2) {
1300 del_on_close = true;
1302 del_on_close = false;
1305 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1306 oplock_level = OPLOCK_NONE;
1307 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1308 oplock_level = OPLOCK_BATCH;
1309 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1310 oplock_level = OPLOCK_EXCLUSIVE;
1313 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1314 allow_level_II_oplock = true;
1317 /* see if we are allowed to open at the same time as existing opens */
1318 status = odb_can_open(lck, name->stream_id,
1319 share_access, access_mask, del_on_close,
1320 io->generic.in.open_disposition, false);
1323 * on a sharing violation we need to retry when the file is closed by
1324 * the other user, or after 1 second
1325 * on a non granted oplock we need to retry when the file is closed by
1326 * the other user, or after 30 seconds
1328 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1329 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1330 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1331 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1334 if (!NT_STATUS_IS_OK(status)) {
1339 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1345 /* do the actual open */
1346 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1348 status = pvfs_map_errno(f->pvfs, errno);
1351 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1353 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1354 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1355 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1364 /* now really mark the file as open */
1365 status = odb_open_file(lck, f->handle, name->full_name,
1366 &f->handle->fd, allow_level_II_oplock,
1367 oplock_level, &oplock_granted);
1369 if (!NT_STATUS_IS_OK(status)) {
1374 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1375 oplock_granted = OPLOCK_BATCH;
1376 } else if (oplock_granted != OPLOCK_NONE) {
1377 status = pvfs_setup_oplock(f, oplock_granted);
1378 if (!NT_STATUS_IS_OK(status)) {
1384 f->handle->have_opendb_entry = true;
1386 stream_existed = name->stream_exists;
1388 /* if this was a stream create then create the stream as well */
1389 if (!name->stream_exists) {
1390 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1391 if (!NT_STATUS_IS_OK(status)) {
1395 if (stream_truncate) {
1396 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1397 if (!NT_STATUS_IS_OK(status)) {
1404 /* re-resolve the open fd */
1405 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1406 if (!NT_STATUS_IS_OK(status)) {
1411 if (f->handle->name->stream_id == 0 &&
1412 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1413 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1414 /* for overwrite we need to replace file permissions */
1415 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1416 mode_t mode = pvfs_fileperms(pvfs, attrib);
1417 if (fchmod(fd, mode) == -1) {
1419 return pvfs_map_errno(pvfs, errno);
1421 name->dos.attrib = attrib;
1422 status = pvfs_dosattrib_save(pvfs, name, fd);
1423 if (!NT_STATUS_IS_OK(status)) {
1431 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1432 NT_STATUS_NOT_OK_RETURN(status);
1434 /* mark the open as having completed fully, so delete on close
1436 f->handle->open_completed = true;
1438 io->generic.out.oplock_level = oplock_granted;
1439 io->generic.out.file.ntvfs = h;
1440 io->generic.out.create_action = stream_existed?
1441 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1442 io->generic.out.create_time = name->dos.create_time;
1443 io->generic.out.access_time = name->dos.access_time;
1444 io->generic.out.write_time = name->dos.write_time;
1445 io->generic.out.change_time = name->dos.change_time;
1446 io->generic.out.attrib = name->dos.attrib;
1447 io->generic.out.alloc_size = name->dos.alloc_size;
1448 io->generic.out.size = name->st.st_size;
1449 io->generic.out.file_type = FILE_TYPE_DISK;
1450 io->generic.out.ipc_state = 0;
1451 io->generic.out.is_directory = 0;
1453 return NT_STATUS_OK;
1460 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1461 struct ntvfs_request *req, union smb_close *io)
1463 struct pvfs_state *pvfs = ntvfs->private_data;
1464 struct pvfs_file *f;
1465 struct utimbuf unix_times;
1467 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1468 return NT_STATUS_DOS(ERRSRV, ERRerror);
1471 if (io->generic.level != RAW_CLOSE_CLOSE) {
1472 return ntvfs_map_close(ntvfs, req, io);
1475 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1477 return NT_STATUS_INVALID_HANDLE;
1480 if (!null_time(io->close.in.write_time)) {
1481 unix_times.actime = 0;
1482 unix_times.modtime = io->close.in.write_time;
1483 utime(f->handle->name->full_name, &unix_times);
1484 } else if (f->handle->sticky_write_time) {
1485 unix_times.actime = 0;
1486 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1487 utime(f->handle->name->full_name, &unix_times);
1492 return NT_STATUS_OK;
1497 logoff - close all file descriptors open by a vuid
1499 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1500 struct ntvfs_request *req)
1502 struct pvfs_state *pvfs = ntvfs->private_data;
1503 struct pvfs_file *f, *next;
1505 for (f=pvfs->files.list;f;f=next) {
1507 if (f->ntvfs->session_info == req->session_info) {
1512 return NT_STATUS_OK;
1517 exit - close files for the current pid
1519 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1520 struct ntvfs_request *req)
1522 struct pvfs_state *pvfs = ntvfs->private_data;
1523 struct pvfs_file *f, *next;
1525 for (f=pvfs->files.list;f;f=next) {
1527 if (f->ntvfs->session_info == req->session_info &&
1528 f->ntvfs->smbpid == req->smbpid) {
1533 return NT_STATUS_OK;
1538 change the delete on close flag on an already open file
1540 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1541 struct ntvfs_request *req,
1542 struct pvfs_file *f, bool del_on_close)
1544 struct odb_lock *lck;
1547 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1548 return NT_STATUS_CANNOT_DELETE;
1551 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1552 !pvfs_directory_empty(pvfs, f->handle->name)) {
1553 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1557 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1559 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1562 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1564 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1567 status = odb_set_delete_on_close(lck, del_on_close);
1576 determine if a file can be deleted, or if it is prevented by an
1579 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1580 struct ntvfs_request *req,
1581 struct pvfs_filename *name,
1582 struct odb_lock **lckp)
1586 struct odb_lock *lck;
1587 uint32_t share_access;
1588 uint32_t access_mask;
1589 bool delete_on_close;
1591 status = pvfs_locking_key(name, name, &key);
1592 if (!NT_STATUS_IS_OK(status)) {
1593 return NT_STATUS_NO_MEMORY;
1596 lck = odb_lock(req, pvfs->odb_context, &key);
1598 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1599 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1602 share_access = NTCREATEX_SHARE_ACCESS_READ |
1603 NTCREATEX_SHARE_ACCESS_WRITE |
1604 NTCREATEX_SHARE_ACCESS_DELETE;
1605 access_mask = SEC_STD_DELETE;
1606 delete_on_close = true;
1608 status = odb_can_open(lck, name->stream_id,
1609 share_access, access_mask, delete_on_close,
1610 NTCREATEX_DISP_OPEN, false);
1612 if (NT_STATUS_IS_OK(status)) {
1613 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1617 * if it's a sharing violation or we got no oplock
1618 * only keep the lock if the caller requested access
1621 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1622 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1628 } else if (!NT_STATUS_IS_OK(status)) {
1641 determine if a file can be renamed, or if it is prevented by an
1644 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1645 struct ntvfs_request *req,
1646 struct pvfs_filename *name,
1647 struct odb_lock **lckp)
1651 struct odb_lock *lck;
1652 uint32_t share_access;
1653 uint32_t access_mask;
1654 bool delete_on_close;
1656 status = pvfs_locking_key(name, name, &key);
1657 if (!NT_STATUS_IS_OK(status)) {
1658 return NT_STATUS_NO_MEMORY;
1661 lck = odb_lock(req, pvfs->odb_context, &key);
1663 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1664 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1667 share_access = NTCREATEX_SHARE_ACCESS_READ |
1668 NTCREATEX_SHARE_ACCESS_WRITE;
1669 access_mask = SEC_STD_DELETE;
1670 delete_on_close = false;
1672 status = odb_can_open(lck, name->stream_id,
1673 share_access, access_mask, delete_on_close,
1674 NTCREATEX_DISP_OPEN, false);
1677 * if it's a sharing violation or we got no oplock
1678 * only keep the lock if the caller requested access
1681 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1682 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1688 } else if (!NT_STATUS_IS_OK(status)) {
1701 determine if the file size of a file can be changed,
1702 or if it is prevented by an already open file
1704 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1705 struct ntvfs_request *req,
1706 struct pvfs_filename *name,
1707 struct odb_lock **lckp)
1711 struct odb_lock *lck;
1712 uint32_t share_access;
1713 uint32_t access_mask;
1715 bool delete_on_close;
1717 status = pvfs_locking_key(name, name, &key);
1718 if (!NT_STATUS_IS_OK(status)) {
1719 return NT_STATUS_NO_MEMORY;
1722 lck = odb_lock(req, pvfs->odb_context, &key);
1724 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1725 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1728 share_access = NTCREATEX_SHARE_ACCESS_READ |
1729 NTCREATEX_SHARE_ACCESS_WRITE |
1730 NTCREATEX_SHARE_ACCESS_DELETE;
1732 * I would have thought that we would need to pass
1733 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1735 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1736 * to set the filesize.
1740 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1741 delete_on_close = false;
1742 break_to_none = true;
1744 status = odb_can_open(lck, name->stream_id,
1745 share_access, access_mask, delete_on_close,
1746 NTCREATEX_DISP_OPEN, break_to_none);
1749 * if it's a sharing violation or we got no oplock
1750 * only keep the lock if the caller requested access
1753 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1754 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1760 } else if (!NT_STATUS_IS_OK(status)) {
1773 determine if file meta data can be accessed, or if it is prevented by an
1776 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1777 struct ntvfs_request *req,
1778 struct pvfs_filename *name)
1782 struct odb_lock *lck;
1783 uint32_t share_access;
1784 uint32_t access_mask;
1785 bool delete_on_close;
1787 status = pvfs_locking_key(name, name, &key);
1788 if (!NT_STATUS_IS_OK(status)) {
1789 return NT_STATUS_NO_MEMORY;
1792 lck = odb_lock(req, pvfs->odb_context, &key);
1794 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1795 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1798 share_access = NTCREATEX_SHARE_ACCESS_READ |
1799 NTCREATEX_SHARE_ACCESS_WRITE;
1800 access_mask = SEC_FILE_READ_ATTRIBUTE;
1801 delete_on_close = false;
1803 status = odb_can_open(lck, name->stream_id,
1804 share_access, access_mask, delete_on_close,
1805 NTCREATEX_DISP_OPEN, false);
1807 if (!NT_STATUS_IS_OK(status)) {
1816 determine if delete on close is set on
1818 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1823 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1825 if (!NT_STATUS_IS_OK(status)) {
1826 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1830 return del_on_close;