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 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 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 */
691 status = odb_open_file(lck, f->handle, name->full_name,
692 allow_level_II_oplock,
693 oplock_level, &oplock_granted);
695 if (!NT_STATUS_IS_OK(status)) {
696 /* bad news, we must have hit a race - we don't delete the file
697 here as the most likely scenario is that someone else created
698 the file at the same time */
706 f->pending_list = NULL;
708 f->share_access = io->generic.in.share_access;
709 f->access_mask = access_mask;
710 f->impersonation = io->generic.in.impersonation;
711 f->notify_buffer = NULL;
714 f->handle->pvfs = pvfs;
715 f->handle->name = talloc_steal(f->handle, name);
717 f->handle->create_options = io->generic.in.create_options;
718 f->handle->seek_offset = 0;
719 f->handle->position = 0;
721 f->handle->oplock = NULL;
722 f->handle->have_opendb_entry = true;
723 f->handle->sticky_write_time = false;
724 f->handle->open_completed = false;
726 DLIST_ADD(pvfs->files.list, f);
728 /* setup a destructor to avoid file descriptor leaks on
729 abnormal termination */
730 talloc_set_destructor(f, pvfs_fnum_destructor);
731 talloc_set_destructor(f->handle, pvfs_handle_destructor);
733 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
734 oplock_granted = OPLOCK_BATCH;
735 } else if (oplock_granted != OPLOCK_NONE) {
736 status = pvfs_setup_oplock(f, oplock_granted);
737 if (!NT_STATUS_IS_OK(status)) {
742 io->generic.out.oplock_level = oplock_granted;
743 io->generic.out.file.ntvfs = f->ntvfs;
744 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
745 io->generic.out.create_time = name->dos.create_time;
746 io->generic.out.access_time = name->dos.access_time;
747 io->generic.out.write_time = name->dos.write_time;
748 io->generic.out.change_time = name->dos.change_time;
749 io->generic.out.attrib = name->dos.attrib;
750 io->generic.out.alloc_size = name->dos.alloc_size;
751 io->generic.out.size = name->st.st_size;
752 io->generic.out.file_type = FILE_TYPE_DISK;
753 io->generic.out.ipc_state = 0;
754 io->generic.out.is_directory = 0;
756 /* success - keep the file handle */
757 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
758 if (!NT_STATUS_IS_OK(status)) {
762 f->handle->open_completed = true;
764 notify_trigger(pvfs->notify_context,
766 FILE_NOTIFY_CHANGE_FILE_NAME,
773 unlink(name->full_name);
778 state of a pending retry
780 struct pvfs_odb_retry {
781 struct ntvfs_module_context *ntvfs;
782 struct ntvfs_request *req;
783 DATA_BLOB odb_locking_key;
786 void (*callback)(struct pvfs_odb_retry *r,
787 struct ntvfs_module_context *ntvfs,
788 struct ntvfs_request *req,
791 enum pvfs_wait_notice reason);
794 /* destroy a pending request */
795 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
797 struct pvfs_state *pvfs = r->ntvfs->private_data;
798 if (r->odb_locking_key.data) {
799 struct odb_lock *lck;
800 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
802 odb_remove_pending(lck, r);
809 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
811 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
813 if (reason == PVFS_WAIT_EVENT) {
815 * The pending odb entry is already removed.
816 * We use a null locking key to indicate this
819 data_blob_free(&r->odb_locking_key);
822 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
826 setup for a retry of a request that was rejected
829 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
830 struct ntvfs_request *req,
831 struct odb_lock *lck,
832 struct timeval end_time,
835 void (*callback)(struct pvfs_odb_retry *r,
836 struct ntvfs_module_context *ntvfs,
837 struct ntvfs_request *req,
840 enum pvfs_wait_notice reason))
842 struct pvfs_state *pvfs = ntvfs->private_data;
843 struct pvfs_odb_retry *r;
844 struct pvfs_wait *wait_handle;
847 r = talloc(req, struct pvfs_odb_retry);
848 NT_STATUS_HAVE_NO_MEMORY(r);
853 r->private_data = private_data;
854 r->callback = callback;
855 r->odb_locking_key = odb_get_key(r, lck);
856 if (r->odb_locking_key.data == NULL) {
857 return NT_STATUS_NO_MEMORY;
860 /* setup a pending lock */
861 status = odb_open_file_pending(lck, r);
862 if (!NT_STATUS_IS_OK(status)) {
868 talloc_set_destructor(r, pvfs_odb_retry_destructor);
870 wait_handle = pvfs_wait_message(pvfs, req,
871 MSG_PVFS_RETRY_OPEN, end_time,
872 pvfs_odb_retry_callback, r);
873 if (wait_handle == NULL) {
874 return NT_STATUS_NO_MEMORY;
877 talloc_steal(r, wait_handle);
879 talloc_steal(pvfs, r);
885 retry an open after a sharing violation
887 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
888 struct ntvfs_module_context *ntvfs,
889 struct ntvfs_request *req,
892 enum pvfs_wait_notice reason)
894 union smb_open *io = talloc_get_type(_io, union smb_open);
897 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
898 just a bug in their server, but we better do the same */
899 if (reason == PVFS_WAIT_CANCEL) {
903 if (reason == PVFS_WAIT_TIMEOUT) {
904 /* if it timed out, then give the failure
907 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
908 req->async_states->send_fn(req);
914 /* try the open again, which could trigger another retry setup
915 if it wants to, so we have to unmark the async flag so we
916 will know if it does a second async reply */
917 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
919 status = pvfs_open(ntvfs, req, io);
920 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
921 /* the 2nd try also replied async, so we don't send
926 /* re-mark it async, just in case someone up the chain does
928 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
930 /* send the reply up the chain */
931 req->async_states->status = status;
932 req->async_states->send_fn(req);
937 special handling for openx DENY_DOS semantics
939 This function attempts a reference open using an existing handle. If its allowed,
940 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
941 open processing continues.
943 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
944 struct ntvfs_request *req, union smb_open *io,
945 struct pvfs_file *f, struct odb_lock *lck)
947 struct pvfs_state *pvfs = ntvfs->private_data;
948 struct pvfs_file *f2;
949 struct pvfs_filename *name;
952 /* search for an existing open with the right parameters. Note
953 the magic ntcreatex options flag, which is set in the
954 generic mapping code. This might look ugly, but its
955 actually pretty much now w2k does it internally as well.
957 If you look at the BASE-DENYDOS test you will see that a
958 DENY_DOS is a very special case, and in the right
959 circumstances you actually get the _same_ handle back
960 twice, rather than a new handle.
962 for (f2=pvfs->files.list;f2;f2=f2->next) {
964 f2->ntvfs->session_info == req->session_info &&
965 f2->ntvfs->smbpid == req->smbpid &&
966 (f2->handle->create_options &
967 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
968 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
969 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
970 strcasecmp_m(f2->handle->name->original_name,
971 io->generic.in.fname)==0) {
977 return NT_STATUS_SHARING_VIOLATION;
980 /* quite an insane set of semantics ... */
981 if (is_exe_filename(io->generic.in.fname) &&
982 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
983 return NT_STATUS_SHARING_VIOLATION;
987 setup a reference to the existing handle
989 talloc_free(f->handle);
990 f->handle = talloc_reference(f, f2->handle);
994 name = f->handle->name;
996 io->generic.out.oplock_level = OPLOCK_NONE;
997 io->generic.out.file.ntvfs = f->ntvfs;
998 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
999 io->generic.out.create_time = name->dos.create_time;
1000 io->generic.out.access_time = name->dos.access_time;
1001 io->generic.out.write_time = name->dos.write_time;
1002 io->generic.out.change_time = name->dos.change_time;
1003 io->generic.out.attrib = name->dos.attrib;
1004 io->generic.out.alloc_size = name->dos.alloc_size;
1005 io->generic.out.size = name->st.st_size;
1006 io->generic.out.file_type = FILE_TYPE_DISK;
1007 io->generic.out.ipc_state = 0;
1008 io->generic.out.is_directory = 0;
1010 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1011 NT_STATUS_NOT_OK_RETURN(status);
1013 return NT_STATUS_OK;
1019 setup for a open retry after a sharing violation
1021 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1022 struct ntvfs_request *req,
1024 struct pvfs_file *f,
1025 struct odb_lock *lck,
1026 NTSTATUS parent_status)
1028 struct pvfs_state *pvfs = ntvfs->private_data;
1030 struct timeval end_time;
1032 if (io->generic.in.create_options &
1033 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1034 /* see if we can satisfy the request using the special DENY_DOS
1036 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1037 if (NT_STATUS_IS_OK(status)) {
1042 /* the retry should allocate a new file handle */
1045 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1046 end_time = timeval_add(&req->statistics.request_time,
1047 0, pvfs->sharing_violation_delay);
1048 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1049 end_time = timeval_add(&req->statistics.request_time,
1050 pvfs->oplock_break_timeout, 0);
1052 return NT_STATUS_INTERNAL_ERROR;
1055 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
1056 pvfs_retry_open_sharing);
1062 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1063 struct ntvfs_request *req, union smb_open *io)
1065 struct pvfs_state *pvfs = ntvfs->private_data;
1067 struct pvfs_filename *name;
1068 struct pvfs_file *f;
1069 struct ntvfs_handle *h;
1072 struct odb_lock *lck;
1073 uint32_t create_options;
1074 uint32_t share_access;
1075 uint32_t access_mask;
1077 bool stream_existed, stream_truncate=false;
1078 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1079 bool allow_level_II_oplock = false;
1081 /* use the generic mapping code to avoid implementing all the
1082 different open calls. */
1083 if (io->generic.level != RAW_OPEN_GENERIC &&
1084 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1085 return ntvfs_map_open(ntvfs, req, io);
1088 /* resolve the cifs name to a posix name */
1089 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1090 PVFS_RESOLVE_STREAMS, &name);
1091 if (!NT_STATUS_IS_OK(status)) {
1095 /* directory opens are handled separately */
1096 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1097 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1098 return pvfs_open_directory(pvfs, req, name, io);
1101 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1102 open doesn't match */
1103 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1105 create_options = io->generic.in.create_options;
1106 share_access = io->generic.in.share_access;
1107 access_mask = io->generic.in.access_mask;
1109 /* certain create options are not allowed */
1110 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1111 !(access_mask & SEC_STD_DELETE)) {
1112 return NT_STATUS_INVALID_PARAMETER;
1117 switch (io->generic.in.open_disposition) {
1118 case NTCREATEX_DISP_SUPERSEDE:
1119 case NTCREATEX_DISP_OVERWRITE_IF:
1120 if (name->stream_name == NULL) {
1123 stream_truncate = true;
1127 case NTCREATEX_DISP_OPEN:
1128 if (!name->stream_exists) {
1129 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1134 case NTCREATEX_DISP_OVERWRITE:
1135 if (!name->stream_exists) {
1136 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1138 if (name->stream_name == NULL) {
1141 stream_truncate = true;
1145 case NTCREATEX_DISP_CREATE:
1146 if (name->stream_exists) {
1147 return NT_STATUS_OBJECT_NAME_COLLISION;
1152 case NTCREATEX_DISP_OPEN_IF:
1157 return NT_STATUS_INVALID_PARAMETER;
1160 /* handle creating a new file separately */
1161 if (!name->exists) {
1162 status = pvfs_create_file(pvfs, req, name, io);
1163 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1167 /* we've hit a race - the file was created during this call */
1168 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1172 /* try re-resolving the name */
1173 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1174 if (!NT_STATUS_IS_OK(status)) {
1177 /* fall through to a normal open */
1180 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1181 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1182 return NT_STATUS_CANNOT_DELETE;
1185 /* check the security descriptor */
1186 status = pvfs_access_check(pvfs, req, name, &access_mask);
1187 if (!NT_STATUS_IS_OK(status)) {
1191 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1192 NT_STATUS_NOT_OK_RETURN(status);
1194 f = talloc(h, struct pvfs_file);
1196 return NT_STATUS_NO_MEMORY;
1199 f->handle = talloc(f, struct pvfs_file_handle);
1200 if (f->handle == NULL) {
1201 return NT_STATUS_NO_MEMORY;
1206 f->pending_list = NULL;
1208 f->share_access = io->generic.in.share_access;
1209 f->access_mask = access_mask;
1210 f->impersonation = io->generic.in.impersonation;
1211 f->notify_buffer = NULL;
1214 f->handle->pvfs = pvfs;
1216 f->handle->name = talloc_steal(f->handle, name);
1217 f->handle->create_options = io->generic.in.create_options;
1218 f->handle->seek_offset = 0;
1219 f->handle->position = 0;
1220 f->handle->mode = 0;
1221 f->handle->oplock = NULL;
1222 f->handle->have_opendb_entry = false;
1223 f->handle->sticky_write_time = false;
1224 f->handle->open_completed = false;
1226 /* form the lock context used for byte range locking and
1228 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1229 if (!NT_STATUS_IS_OK(status)) {
1233 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1234 if (!NT_STATUS_IS_OK(status)) {
1238 /* get a lock on this file before the actual open */
1239 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1241 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1243 /* we were supposed to do a blocking lock, so something
1245 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1248 DLIST_ADD(pvfs->files.list, f);
1250 /* setup a destructor to avoid file descriptor leaks on
1251 abnormal termination */
1252 talloc_set_destructor(f, pvfs_fnum_destructor);
1253 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1256 * Only SMB2 takes care of the delete_on_close,
1259 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1260 req->ctx->protocol == PROTOCOL_SMB2) {
1261 del_on_close = true;
1263 del_on_close = false;
1266 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1267 oplock_level = OPLOCK_NONE;
1268 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1269 oplock_level = OPLOCK_BATCH;
1270 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1271 oplock_level = OPLOCK_EXCLUSIVE;
1274 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1275 allow_level_II_oplock = true;
1278 /* see if we are allowed to open at the same time as existing opens */
1279 status = odb_can_open(lck, name->stream_id,
1280 share_access, access_mask, del_on_close,
1281 io->generic.in.open_disposition, false);
1284 * on a sharing violation we need to retry when the file is closed by
1285 * the other user, or after 1 second
1286 * on a non granted oplock we need to retry when the file is closed by
1287 * the other user, or after 30 seconds
1289 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1290 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1291 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1292 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1295 if (!NT_STATUS_IS_OK(status)) {
1300 /* now really mark the file as open */
1301 status = odb_open_file(lck, f->handle, name->full_name,
1302 allow_level_II_oplock,
1303 oplock_level, &oplock_granted);
1305 if (!NT_STATUS_IS_OK(status)) {
1310 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1311 oplock_granted = OPLOCK_BATCH;
1312 } else if (oplock_granted != OPLOCK_NONE) {
1313 status = pvfs_setup_oplock(f, oplock_granted);
1314 if (!NT_STATUS_IS_OK(status)) {
1320 f->handle->have_opendb_entry = true;
1322 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1328 /* do the actual open */
1329 fd = open(f->handle->name->full_name, flags);
1332 return pvfs_map_errno(f->pvfs, errno);
1337 stream_existed = name->stream_exists;
1339 /* if this was a stream create then create the stream as well */
1340 if (!name->stream_exists) {
1341 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1342 if (!NT_STATUS_IS_OK(status)) {
1346 if (stream_truncate) {
1347 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1348 if (!NT_STATUS_IS_OK(status)) {
1355 /* re-resolve the open fd */
1356 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1357 if (!NT_STATUS_IS_OK(status)) {
1362 if (f->handle->name->stream_id == 0 &&
1363 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1364 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1365 /* for overwrite we need to replace file permissions */
1366 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1367 mode_t mode = pvfs_fileperms(pvfs, attrib);
1368 if (fchmod(fd, mode) == -1) {
1370 return pvfs_map_errno(pvfs, errno);
1372 name->dos.attrib = attrib;
1373 status = pvfs_dosattrib_save(pvfs, name, fd);
1374 if (!NT_STATUS_IS_OK(status)) {
1382 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1383 NT_STATUS_NOT_OK_RETURN(status);
1385 /* mark the open as having completed fully, so delete on close
1387 f->handle->open_completed = true;
1389 io->generic.out.oplock_level = oplock_granted;
1390 io->generic.out.file.ntvfs = h;
1391 io->generic.out.create_action = stream_existed?
1392 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1393 io->generic.out.create_time = name->dos.create_time;
1394 io->generic.out.access_time = name->dos.access_time;
1395 io->generic.out.write_time = name->dos.write_time;
1396 io->generic.out.change_time = name->dos.change_time;
1397 io->generic.out.attrib = name->dos.attrib;
1398 io->generic.out.alloc_size = name->dos.alloc_size;
1399 io->generic.out.size = name->st.st_size;
1400 io->generic.out.file_type = FILE_TYPE_DISK;
1401 io->generic.out.ipc_state = 0;
1402 io->generic.out.is_directory = 0;
1404 return NT_STATUS_OK;
1411 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1412 struct ntvfs_request *req, union smb_close *io)
1414 struct pvfs_state *pvfs = ntvfs->private_data;
1415 struct pvfs_file *f;
1416 struct utimbuf unix_times;
1418 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1419 return NT_STATUS_DOS(ERRSRV, ERRerror);
1422 if (io->generic.level != RAW_CLOSE_CLOSE) {
1423 return ntvfs_map_close(ntvfs, req, io);
1426 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1428 return NT_STATUS_INVALID_HANDLE;
1431 if (!null_time(io->close.in.write_time)) {
1432 unix_times.actime = 0;
1433 unix_times.modtime = io->close.in.write_time;
1434 utime(f->handle->name->full_name, &unix_times);
1435 } else if (f->handle->sticky_write_time) {
1436 unix_times.actime = 0;
1437 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1438 utime(f->handle->name->full_name, &unix_times);
1443 return NT_STATUS_OK;
1448 logoff - close all file descriptors open by a vuid
1450 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1451 struct ntvfs_request *req)
1453 struct pvfs_state *pvfs = ntvfs->private_data;
1454 struct pvfs_file *f, *next;
1456 for (f=pvfs->files.list;f;f=next) {
1458 if (f->ntvfs->session_info == req->session_info) {
1463 return NT_STATUS_OK;
1468 exit - close files for the current pid
1470 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1471 struct ntvfs_request *req)
1473 struct pvfs_state *pvfs = ntvfs->private_data;
1474 struct pvfs_file *f, *next;
1476 for (f=pvfs->files.list;f;f=next) {
1478 if (f->ntvfs->session_info == req->session_info &&
1479 f->ntvfs->smbpid == req->smbpid) {
1484 return NT_STATUS_OK;
1489 change the delete on close flag on an already open file
1491 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1492 struct ntvfs_request *req,
1493 struct pvfs_file *f, bool del_on_close)
1495 struct odb_lock *lck;
1498 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1499 return NT_STATUS_CANNOT_DELETE;
1502 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1503 !pvfs_directory_empty(pvfs, f->handle->name)) {
1504 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1508 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1510 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1513 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1515 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1518 status = odb_set_delete_on_close(lck, del_on_close);
1527 determine if a file can be deleted, or if it is prevented by an
1530 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1531 struct ntvfs_request *req,
1532 struct pvfs_filename *name,
1533 struct odb_lock **lckp)
1537 struct odb_lock *lck;
1538 uint32_t share_access;
1539 uint32_t access_mask;
1540 bool delete_on_close;
1542 status = pvfs_locking_key(name, name, &key);
1543 if (!NT_STATUS_IS_OK(status)) {
1544 return NT_STATUS_NO_MEMORY;
1547 lck = odb_lock(req, pvfs->odb_context, &key);
1549 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1550 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1553 share_access = NTCREATEX_SHARE_ACCESS_READ |
1554 NTCREATEX_SHARE_ACCESS_WRITE |
1555 NTCREATEX_SHARE_ACCESS_DELETE;
1556 access_mask = SEC_STD_DELETE;
1557 delete_on_close = true;
1559 status = odb_can_open(lck, name->stream_id,
1560 share_access, access_mask, delete_on_close,
1561 NTCREATEX_DISP_OPEN, false);
1563 if (NT_STATUS_IS_OK(status)) {
1564 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1568 * if it's a sharing violation or we got no oplock
1569 * only keep the lock if the caller requested access
1572 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1573 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1579 } else if (!NT_STATUS_IS_OK(status)) {
1592 determine if a file can be renamed, or if it is prevented by an
1595 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1596 struct ntvfs_request *req,
1597 struct pvfs_filename *name,
1598 struct odb_lock **lckp)
1602 struct odb_lock *lck;
1603 uint32_t share_access;
1604 uint32_t access_mask;
1605 bool delete_on_close;
1607 status = pvfs_locking_key(name, name, &key);
1608 if (!NT_STATUS_IS_OK(status)) {
1609 return NT_STATUS_NO_MEMORY;
1612 lck = odb_lock(req, pvfs->odb_context, &key);
1614 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1615 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1618 share_access = NTCREATEX_SHARE_ACCESS_READ |
1619 NTCREATEX_SHARE_ACCESS_WRITE;
1620 access_mask = SEC_STD_DELETE;
1621 delete_on_close = false;
1623 status = odb_can_open(lck, name->stream_id,
1624 share_access, access_mask, delete_on_close,
1625 NTCREATEX_DISP_OPEN, false);
1628 * if it's a sharing violation or we got no oplock
1629 * only keep the lock if the caller requested access
1632 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1633 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1639 } else if (!NT_STATUS_IS_OK(status)) {
1652 determine if the file size of a file can be changed,
1653 or if it is prevented by an already open file
1655 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1656 struct ntvfs_request *req,
1657 struct pvfs_filename *name,
1658 struct odb_lock **lckp)
1662 struct odb_lock *lck;
1663 uint32_t share_access;
1664 uint32_t access_mask;
1666 bool delete_on_close;
1668 status = pvfs_locking_key(name, name, &key);
1669 if (!NT_STATUS_IS_OK(status)) {
1670 return NT_STATUS_NO_MEMORY;
1673 lck = odb_lock(req, pvfs->odb_context, &key);
1675 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1676 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1679 share_access = NTCREATEX_SHARE_ACCESS_READ |
1680 NTCREATEX_SHARE_ACCESS_WRITE |
1681 NTCREATEX_SHARE_ACCESS_DELETE;
1683 * I would have thought that we would need to pass
1684 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1686 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1687 * to set the filesize.
1691 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1692 delete_on_close = false;
1693 break_to_none = true;
1695 status = odb_can_open(lck, name->stream_id,
1696 share_access, access_mask, delete_on_close,
1697 NTCREATEX_DISP_OPEN, break_to_none);
1700 * if it's a sharing violation or we got no oplock
1701 * only keep the lock if the caller requested access
1704 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1705 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1711 } else if (!NT_STATUS_IS_OK(status)) {
1724 determine if file meta data can be accessed, or if it is prevented by an
1727 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1728 struct ntvfs_request *req,
1729 struct pvfs_filename *name)
1733 struct odb_lock *lck;
1734 uint32_t share_access;
1735 uint32_t access_mask;
1736 bool delete_on_close;
1738 status = pvfs_locking_key(name, name, &key);
1739 if (!NT_STATUS_IS_OK(status)) {
1740 return NT_STATUS_NO_MEMORY;
1743 lck = odb_lock(req, pvfs->odb_context, &key);
1745 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1746 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1749 share_access = NTCREATEX_SHARE_ACCESS_READ |
1750 NTCREATEX_SHARE_ACCESS_WRITE;
1751 access_mask = SEC_FILE_READ_ATTRIBUTE;
1752 delete_on_close = false;
1754 status = odb_can_open(lck, name->stream_id,
1755 share_access, access_mask, delete_on_close,
1756 NTCREATEX_DISP_OPEN, false);
1758 if (!NT_STATUS_IS_OK(status)) {
1767 determine if delete on close is set on
1769 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1774 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1776 if (!NT_STATUS_IS_OK(status)) {
1777 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1781 return del_on_close;