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)
56 if (h->name->stream_name == NULL &&
57 pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
60 status = pvfs_xattr_unlink_hook(h->pvfs, path);
61 if (!NT_STATUS_IS_OK(status)) {
62 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
63 path, nt_errstr(status)));
65 if (rmdir(path) != 0) {
66 DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
67 path, strerror(errno)));
73 if (h->have_opendb_entry) {
77 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
79 DEBUG(0,("Unable to lock opendb for close\n"));
83 status = odb_close_file(lck, h);
84 if (!NT_STATUS_IS_OK(status)) {
85 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
86 h->name->full_name, nt_errstr(status)));
96 cleanup a open directory fnum
98 static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
100 DLIST_REMOVE(f->pvfs->files.list, f);
101 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
107 setup any EAs and the ACL on newly created files/directories
109 static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
110 struct ntvfs_request *req,
111 struct pvfs_filename *name,
112 int fd, struct pvfs_file *f,
117 /* setup any EAs that were asked for */
118 if (io->ntcreatex.in.ea_list) {
119 status = pvfs_setfileinfo_ea_set(pvfs, name, fd,
120 io->ntcreatex.in.ea_list->num_eas,
121 io->ntcreatex.in.ea_list->eas);
122 if (!NT_STATUS_IS_OK(status)) {
127 /* setup an initial sec_desc if requested */
128 if (io->ntcreatex.in.sec_desc) {
129 union smb_setfileinfo set;
131 * TODO: set the full ACL!
132 * - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
133 * when a SACL is present on the sd,
134 * but the user doesn't have SeSecurityPrivilege
137 set.set_secdesc.in.file.ntvfs = f->ntvfs;
138 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
139 set.set_secdesc.in.sd = io->ntcreatex.in.sec_desc;
141 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
143 /* otherwise setup an inherited acl from the parent */
144 status = pvfs_acl_inherit(pvfs, req, name, fd);
151 form the lock context used for opendb locking. Note that we must
152 zero here to take account of possible padding on some architectures
154 static NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
155 TALLOC_CTX *mem_ctx, DATA_BLOB *key)
161 ZERO_STRUCT(lock_context);
163 lock_context.device = name->st.st_dev;
164 lock_context.inode = name->st.st_ino;
166 *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
167 if (key->data == NULL) {
168 return NT_STATUS_NO_MEMORY;
178 static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
179 struct ntvfs_request *req,
180 struct pvfs_filename *name,
184 struct ntvfs_handle *h;
186 uint32_t create_action;
187 uint32_t access_mask = io->generic.in.access_mask;
188 struct odb_lock *lck;
190 uint32_t create_options;
191 uint32_t share_access;
193 create_options = io->generic.in.create_options;
194 share_access = io->generic.in.share_access;
196 if (name->stream_name) {
197 return NT_STATUS_NOT_A_DIRECTORY;
200 /* if the client says it must be a directory, and it isn't,
202 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
203 return NT_STATUS_NOT_A_DIRECTORY;
206 switch (io->generic.in.open_disposition) {
207 case NTCREATEX_DISP_OPEN_IF:
210 case NTCREATEX_DISP_OPEN:
212 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
216 case NTCREATEX_DISP_CREATE:
218 return NT_STATUS_OBJECT_NAME_COLLISION;
222 case NTCREATEX_DISP_OVERWRITE_IF:
223 case NTCREATEX_DISP_OVERWRITE:
224 case NTCREATEX_DISP_SUPERSEDE:
226 return NT_STATUS_INVALID_PARAMETER;
229 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
230 NT_STATUS_NOT_OK_RETURN(status);
232 f = talloc(h, struct pvfs_file);
234 return NT_STATUS_NO_MEMORY;
237 f->handle = talloc(f, struct pvfs_file_handle);
238 if (f->handle == NULL) {
239 return NT_STATUS_NO_MEMORY;
243 /* check the security descriptor */
244 status = pvfs_access_check(pvfs, req, name, &access_mask);
246 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
248 if (!NT_STATUS_IS_OK(status)) {
254 f->pending_list = NULL;
256 f->share_access = io->generic.in.share_access;
257 f->impersonation = io->generic.in.impersonation;
258 f->access_mask = access_mask;
259 f->brl_handle = NULL;
260 f->notify_buffer = NULL;
263 f->handle->pvfs = pvfs;
264 f->handle->name = talloc_steal(f->handle, name);
266 f->handle->odb_locking_key = data_blob(NULL, 0);
267 f->handle->create_options = io->generic.in.create_options;
268 f->handle->seek_offset = 0;
269 f->handle->position = 0;
271 f->handle->oplock = NULL;
272 f->handle->sticky_write_time = false;
273 f->handle->open_completed = false;
275 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
276 pvfs_directory_empty(pvfs, f->handle->name)) {
279 del_on_close = false;
283 /* form the lock context used for opendb locking */
284 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
285 if (!NT_STATUS_IS_OK(status)) {
289 /* get a lock on this file before the actual open */
290 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
292 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
294 /* we were supposed to do a blocking lock, so something
296 return NT_STATUS_INTERNAL_DB_CORRUPTION;
299 /* see if we are allowed to open at the same time as existing opens */
300 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
301 share_access, access_mask, del_on_close,
302 io->generic.in.open_disposition,
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_open_file(lck, f->handle, name->full_name, name->stream_id,
355 share_access, access_mask, del_on_close,
356 io->generic.in.open_disposition,
357 false, OPLOCK_NONE, NULL);
359 if (!NT_STATUS_IS_OK(status)) {
363 f->handle->have_opendb_entry = true;
365 create_action = NTCREATEX_ACTION_CREATED;
367 notify_trigger(pvfs->notify_context,
369 FILE_NOTIFY_CHANGE_DIR_NAME,
372 create_action = NTCREATEX_ACTION_EXISTED;
376 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
379 /* the open succeeded, keep this handle permanently */
380 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
381 if (!NT_STATUS_IS_OK(status)) {
385 f->handle->open_completed = true;
387 io->generic.out.oplock_level = OPLOCK_NONE;
388 io->generic.out.file.ntvfs = h;
389 io->generic.out.create_action = create_action;
390 io->generic.out.create_time = name->dos.create_time;
391 io->generic.out.access_time = name->dos.access_time;
392 io->generic.out.write_time = name->dos.write_time;
393 io->generic.out.change_time = name->dos.change_time;
394 io->generic.out.attrib = name->dos.attrib;
395 io->generic.out.alloc_size = name->dos.alloc_size;
396 io->generic.out.size = name->st.st_size;
397 io->generic.out.file_type = FILE_TYPE_DISK;
398 io->generic.out.ipc_state = 0;
399 io->generic.out.is_directory = 1;
404 rmdir(name->full_name);
409 destroy a struct pvfs_file_handle
411 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
416 /* the write time is no longer sticky */
417 if (h->sticky_write_time) {
419 status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
420 if (NT_STATUS_IS_OK(status)) {
421 h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
422 pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
426 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
427 h->name->stream_name) {
429 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
430 if (!NT_STATUS_IS_OK(status)) {
431 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
432 h->name->stream_name, h->name->full_name));
437 if (close(h->fd) != 0) {
438 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
439 h->fd, h->name->full_name, strerror(errno)));
444 if (h->name->stream_name == NULL &&
446 pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
449 status = pvfs_xattr_unlink_hook(h->pvfs, path);
450 if (!NT_STATUS_IS_OK(status)) {
451 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
452 path, nt_errstr(status)));
454 if (unlink(path) != 0) {
455 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
456 path, strerror(errno)));
458 notify_trigger(h->pvfs->notify_context,
459 NOTIFY_ACTION_REMOVED,
460 FILE_NOTIFY_CHANGE_FILE_NAME,
467 if (h->have_opendb_entry) {
468 struct odb_lock *lck;
471 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
473 DEBUG(0,("Unable to lock opendb for close\n"));
477 status = odb_close_file(lck, h);
478 if (!NT_STATUS_IS_OK(status)) {
479 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
480 h->name->full_name, nt_errstr(status)));
491 destroy a struct pvfs_file
493 static int pvfs_fnum_destructor(struct pvfs_file *f)
495 DLIST_REMOVE(f->pvfs->files.list, f);
496 pvfs_lock_close(f->pvfs, f);
497 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
504 form the lock context used for byte range locking. This is separate
505 from the locking key used for opendb locking as it needs to take
506 account of file streams (each stream is a separate byte range
509 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
510 struct pvfs_filename *name,
511 struct ntvfs_handle *ntvfs,
512 struct brl_handle **_h)
514 DATA_BLOB odb_key, key;
516 struct brl_handle *h;
518 status = pvfs_locking_key(name, mem_ctx, &odb_key);
519 NT_STATUS_NOT_OK_RETURN(status);
521 if (name->stream_name == NULL) {
524 key = data_blob_talloc(mem_ctx, NULL,
525 odb_key.length + strlen(name->stream_name) + 1);
526 NT_STATUS_HAVE_NO_MEMORY(key.data);
527 memcpy(key.data, odb_key.data, odb_key.length);
528 memcpy(key.data + odb_key.length,
529 name->stream_name, strlen(name->stream_name) + 1);
530 data_blob_free(&odb_key);
533 h = brl_create_handle(mem_ctx, ntvfs, &key);
534 NT_STATUS_HAVE_NO_MEMORY(h);
543 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
544 struct ntvfs_request *req,
545 struct pvfs_filename *name,
550 struct ntvfs_handle *h;
552 struct odb_lock *lck;
553 uint32_t create_options = io->generic.in.create_options;
554 uint32_t share_access = io->generic.in.share_access;
555 uint32_t access_mask = io->generic.in.access_mask;
559 struct pvfs_filename *parent;
560 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
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,
577 &del_on_close, NULL, NULL);
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 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
676 share_access, access_mask, del_on_close,
677 io->generic.in.open_disposition,
678 false, oplock_level, &oplock_granted);
680 if (!NT_STATUS_IS_OK(status)) {
681 /* bad news, we must have hit a race - we don't delete the file
682 here as the most likely scenario is that someone else created
683 the file at the same time */
691 f->pending_list = NULL;
693 f->share_access = io->generic.in.share_access;
694 f->access_mask = access_mask;
695 f->impersonation = io->generic.in.impersonation;
696 f->notify_buffer = NULL;
699 f->handle->pvfs = pvfs;
700 f->handle->name = talloc_steal(f->handle, name);
702 f->handle->create_options = io->generic.in.create_options;
703 f->handle->seek_offset = 0;
704 f->handle->position = 0;
706 f->handle->oplock = NULL;
707 f->handle->have_opendb_entry = true;
708 f->handle->sticky_write_time = false;
709 f->handle->open_completed = false;
711 DLIST_ADD(pvfs->files.list, f);
713 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
714 oplock_granted = OPLOCK_BATCH;
715 } else if (oplock_granted != OPLOCK_NONE) {
716 status = pvfs_setup_oplock(f, oplock_granted);
717 if (!NT_STATUS_IS_OK(status)) {
723 /* setup a destructor to avoid file descriptor leaks on
724 abnormal termination */
725 talloc_set_destructor(f, pvfs_fnum_destructor);
726 talloc_set_destructor(f->handle, pvfs_handle_destructor);
728 io->generic.out.oplock_level = oplock_granted;
729 io->generic.out.file.ntvfs = f->ntvfs;
730 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
731 io->generic.out.create_time = name->dos.create_time;
732 io->generic.out.access_time = name->dos.access_time;
733 io->generic.out.write_time = name->dos.write_time;
734 io->generic.out.change_time = name->dos.change_time;
735 io->generic.out.attrib = name->dos.attrib;
736 io->generic.out.alloc_size = name->dos.alloc_size;
737 io->generic.out.size = name->st.st_size;
738 io->generic.out.file_type = FILE_TYPE_DISK;
739 io->generic.out.ipc_state = 0;
740 io->generic.out.is_directory = 0;
742 /* success - keep the file handle */
743 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
744 if (!NT_STATUS_IS_OK(status)) {
748 f->handle->open_completed = true;
750 notify_trigger(pvfs->notify_context,
752 FILE_NOTIFY_CHANGE_FILE_NAME,
759 unlink(name->full_name);
764 state of a pending retry
766 struct pvfs_odb_retry {
767 struct ntvfs_module_context *ntvfs;
768 struct ntvfs_request *req;
769 DATA_BLOB odb_locking_key;
772 void (*callback)(struct pvfs_odb_retry *r,
773 struct ntvfs_module_context *ntvfs,
774 struct ntvfs_request *req,
777 enum pvfs_wait_notice reason);
780 /* destroy a pending request */
781 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
783 struct pvfs_state *pvfs = r->ntvfs->private_data;
784 if (r->odb_locking_key.data) {
785 struct odb_lock *lck;
786 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
788 odb_remove_pending(lck, r);
795 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
797 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
799 if (reason == PVFS_WAIT_EVENT) {
801 * The pending odb entry is already removed.
802 * We use a null locking key to indicate this
805 data_blob_free(&r->odb_locking_key);
808 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
812 setup for a retry of a request that was rejected
813 by odb_open_file() or odb_can_open()
815 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
816 struct ntvfs_request *req,
817 struct odb_lock *lck,
818 struct timeval end_time,
821 void (*callback)(struct pvfs_odb_retry *r,
822 struct ntvfs_module_context *ntvfs,
823 struct ntvfs_request *req,
826 enum pvfs_wait_notice reason))
828 struct pvfs_state *pvfs = ntvfs->private_data;
829 struct pvfs_odb_retry *r;
830 struct pvfs_wait *wait_handle;
833 r = talloc(req, struct pvfs_odb_retry);
834 NT_STATUS_HAVE_NO_MEMORY(r);
839 r->private_data = private_data;
840 r->callback = callback;
841 r->odb_locking_key = odb_get_key(r, lck);
842 if (r->odb_locking_key.data == NULL) {
843 return NT_STATUS_NO_MEMORY;
846 /* setup a pending lock */
847 status = odb_open_file_pending(lck, r);
848 if (!NT_STATUS_IS_OK(status)) {
854 talloc_set_destructor(r, pvfs_odb_retry_destructor);
856 wait_handle = pvfs_wait_message(pvfs, req,
857 MSG_PVFS_RETRY_OPEN, end_time,
858 pvfs_odb_retry_callback, r);
859 if (wait_handle == NULL) {
860 return NT_STATUS_NO_MEMORY;
863 talloc_steal(r, wait_handle);
865 talloc_steal(pvfs, r);
871 retry an open after a sharing violation
873 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
874 struct ntvfs_module_context *ntvfs,
875 struct ntvfs_request *req,
878 enum pvfs_wait_notice reason)
880 union smb_open *io = talloc_get_type(_io, union smb_open);
883 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
884 just a bug in their server, but we better do the same */
885 if (reason == PVFS_WAIT_CANCEL) {
889 if (reason == PVFS_WAIT_TIMEOUT) {
890 /* if it timed out, then give the failure
893 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
894 req->async_states->send_fn(req);
900 /* try the open again, which could trigger another retry setup
901 if it wants to, so we have to unmark the async flag so we
902 will know if it does a second async reply */
903 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
905 status = pvfs_open(ntvfs, req, io);
906 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
907 /* the 2nd try also replied async, so we don't send
912 /* re-mark it async, just in case someone up the chain does
914 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
916 /* send the reply up the chain */
917 req->async_states->status = status;
918 req->async_states->send_fn(req);
923 special handling for openx DENY_DOS semantics
925 This function attempts a reference open using an existing handle. If its allowed,
926 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
927 open processing continues.
929 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
930 struct ntvfs_request *req, union smb_open *io,
931 struct pvfs_file *f, struct odb_lock *lck)
933 struct pvfs_state *pvfs = ntvfs->private_data;
934 struct pvfs_file *f2;
935 struct pvfs_filename *name;
938 /* search for an existing open with the right parameters. Note
939 the magic ntcreatex options flag, which is set in the
940 generic mapping code. This might look ugly, but its
941 actually pretty much now w2k does it internally as well.
943 If you look at the BASE-DENYDOS test you will see that a
944 DENY_DOS is a very special case, and in the right
945 circumstances you actually get the _same_ handle back
946 twice, rather than a new handle.
948 for (f2=pvfs->files.list;f2;f2=f2->next) {
950 f2->ntvfs->session_info == req->session_info &&
951 f2->ntvfs->smbpid == req->smbpid &&
952 (f2->handle->create_options &
953 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
954 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
955 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
956 strcasecmp_m(f2->handle->name->original_name,
957 io->generic.in.fname)==0) {
963 return NT_STATUS_SHARING_VIOLATION;
966 /* quite an insane set of semantics ... */
967 if (is_exe_filename(io->generic.in.fname) &&
968 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
969 return NT_STATUS_SHARING_VIOLATION;
973 setup a reference to the existing handle
975 talloc_free(f->handle);
976 f->handle = talloc_reference(f, f2->handle);
980 name = f->handle->name;
982 io->generic.out.oplock_level = OPLOCK_NONE;
983 io->generic.out.file.ntvfs = f->ntvfs;
984 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
985 io->generic.out.create_time = name->dos.create_time;
986 io->generic.out.access_time = name->dos.access_time;
987 io->generic.out.write_time = name->dos.write_time;
988 io->generic.out.change_time = name->dos.change_time;
989 io->generic.out.attrib = name->dos.attrib;
990 io->generic.out.alloc_size = name->dos.alloc_size;
991 io->generic.out.size = name->st.st_size;
992 io->generic.out.file_type = FILE_TYPE_DISK;
993 io->generic.out.ipc_state = 0;
994 io->generic.out.is_directory = 0;
996 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
997 NT_STATUS_NOT_OK_RETURN(status);
1005 setup for a open retry after a sharing violation
1007 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1008 struct ntvfs_request *req,
1010 struct pvfs_file *f,
1011 struct odb_lock *lck)
1013 struct pvfs_state *pvfs = ntvfs->private_data;
1015 struct timeval end_time;
1017 if (io->generic.in.create_options &
1018 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1019 /* see if we can satisfy the request using the special DENY_DOS
1021 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1022 if (NT_STATUS_IS_OK(status)) {
1027 /* the retry should allocate a new file handle */
1030 end_time = timeval_add(&req->statistics.request_time, 0, pvfs->sharing_violation_delay);
1032 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
1033 pvfs_retry_open_sharing);
1039 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1040 struct ntvfs_request *req, union smb_open *io)
1042 struct pvfs_state *pvfs = ntvfs->private_data;
1044 struct pvfs_filename *name;
1045 struct pvfs_file *f;
1046 struct ntvfs_handle *h;
1049 struct odb_lock *lck;
1050 uint32_t create_options;
1051 uint32_t share_access;
1052 uint32_t access_mask;
1054 bool stream_existed, stream_truncate=false;
1055 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1057 /* use the generic mapping code to avoid implementing all the
1058 different open calls. */
1059 if (io->generic.level != RAW_OPEN_GENERIC &&
1060 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1061 return ntvfs_map_open(ntvfs, req, io);
1064 /* resolve the cifs name to a posix name */
1065 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1066 PVFS_RESOLVE_STREAMS, &name);
1067 if (!NT_STATUS_IS_OK(status)) {
1071 /* directory opens are handled separately */
1072 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1073 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1074 return pvfs_open_directory(pvfs, req, name, io);
1077 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1078 open doesn't match */
1079 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1081 create_options = io->generic.in.create_options;
1082 share_access = io->generic.in.share_access;
1083 access_mask = io->generic.in.access_mask;
1085 /* certain create options are not allowed */
1086 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1087 !(access_mask & SEC_STD_DELETE)) {
1088 return NT_STATUS_INVALID_PARAMETER;
1093 switch (io->generic.in.open_disposition) {
1094 case NTCREATEX_DISP_SUPERSEDE:
1095 case NTCREATEX_DISP_OVERWRITE_IF:
1096 if (name->stream_name == NULL) {
1099 stream_truncate = true;
1103 case NTCREATEX_DISP_OPEN:
1104 if (!name->stream_exists) {
1105 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1110 case NTCREATEX_DISP_OVERWRITE:
1111 if (!name->stream_exists) {
1112 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1114 if (name->stream_name == NULL) {
1117 stream_truncate = true;
1121 case NTCREATEX_DISP_CREATE:
1122 if (name->stream_exists) {
1123 return NT_STATUS_OBJECT_NAME_COLLISION;
1128 case NTCREATEX_DISP_OPEN_IF:
1133 return NT_STATUS_INVALID_PARAMETER;
1136 /* handle creating a new file separately */
1137 if (!name->exists) {
1138 status = pvfs_create_file(pvfs, req, name, io);
1139 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1143 /* we've hit a race - the file was created during this call */
1144 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1148 /* try re-resolving the name */
1149 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1150 if (!NT_STATUS_IS_OK(status)) {
1153 /* fall through to a normal open */
1156 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1157 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1158 return NT_STATUS_CANNOT_DELETE;
1161 /* check the security descriptor */
1162 status = pvfs_access_check(pvfs, req, name, &access_mask);
1163 if (!NT_STATUS_IS_OK(status)) {
1167 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1168 NT_STATUS_NOT_OK_RETURN(status);
1170 f = talloc(h, struct pvfs_file);
1172 return NT_STATUS_NO_MEMORY;
1175 f->handle = talloc(f, struct pvfs_file_handle);
1176 if (f->handle == NULL) {
1177 return NT_STATUS_NO_MEMORY;
1182 f->pending_list = NULL;
1184 f->share_access = io->generic.in.share_access;
1185 f->access_mask = access_mask;
1186 f->impersonation = io->generic.in.impersonation;
1187 f->notify_buffer = NULL;
1190 f->handle->pvfs = pvfs;
1192 f->handle->name = talloc_steal(f->handle, name);
1193 f->handle->create_options = io->generic.in.create_options;
1194 f->handle->seek_offset = 0;
1195 f->handle->position = 0;
1196 f->handle->mode = 0;
1197 f->handle->oplock = NULL;
1198 f->handle->have_opendb_entry = false;
1199 f->handle->sticky_write_time = false;
1200 f->handle->open_completed = false;
1202 /* form the lock context used for byte range locking and
1204 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1205 if (!NT_STATUS_IS_OK(status)) {
1209 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1210 if (!NT_STATUS_IS_OK(status)) {
1214 /* get a lock on this file before the actual open */
1215 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1217 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1219 /* we were supposed to do a blocking lock, so something
1221 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1224 DLIST_ADD(pvfs->files.list, f);
1226 /* setup a destructor to avoid file descriptor leaks on
1227 abnormal termination */
1228 talloc_set_destructor(f, pvfs_fnum_destructor);
1229 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1232 * Only SMB2 takes care of the delete_on_close,
1235 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1236 req->ctx->protocol == PROTOCOL_SMB2) {
1237 del_on_close = true;
1239 del_on_close = false;
1242 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1243 oplock_level = OPLOCK_NONE;
1244 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1245 oplock_level = OPLOCK_BATCH;
1246 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1247 oplock_level = OPLOCK_EXCLUSIVE;
1250 /* see if we are allowed to open at the same time as existing opens */
1251 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
1252 share_access, access_mask, del_on_close,
1253 io->generic.in.open_disposition,
1254 false, oplock_level, &oplock_granted);
1256 /* on a sharing violation we need to retry when the file is closed by
1257 the other user, or after 1 second */
1258 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) &&
1259 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1260 return pvfs_open_setup_retry(ntvfs, req, io, f, lck);
1263 if (!NT_STATUS_IS_OK(status)) {
1268 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1269 oplock_granted = OPLOCK_BATCH;
1270 } else if (oplock_granted != OPLOCK_NONE) {
1271 status = pvfs_setup_oplock(f, oplock_granted);
1272 if (!NT_STATUS_IS_OK(status)) {
1278 f->handle->have_opendb_entry = true;
1280 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1286 /* do the actual open */
1287 fd = open(f->handle->name->full_name, flags);
1290 return pvfs_map_errno(f->pvfs, errno);
1295 stream_existed = name->stream_exists;
1297 /* if this was a stream create then create the stream as well */
1298 if (!name->stream_exists) {
1299 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1300 if (!NT_STATUS_IS_OK(status)) {
1304 if (stream_truncate) {
1305 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1306 if (!NT_STATUS_IS_OK(status)) {
1313 /* re-resolve the open fd */
1314 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1315 if (!NT_STATUS_IS_OK(status)) {
1320 if (f->handle->name->stream_id == 0 &&
1321 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1322 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1323 /* for overwrite we need to replace file permissions */
1324 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1325 mode_t mode = pvfs_fileperms(pvfs, attrib);
1326 if (fchmod(fd, mode) == -1) {
1328 return pvfs_map_errno(pvfs, errno);
1330 name->dos.attrib = attrib;
1331 status = pvfs_dosattrib_save(pvfs, name, fd);
1332 if (!NT_STATUS_IS_OK(status)) {
1340 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1341 NT_STATUS_NOT_OK_RETURN(status);
1343 /* mark the open as having completed fully, so delete on close
1345 f->handle->open_completed = true;
1347 io->generic.out.oplock_level = oplock_granted;
1348 io->generic.out.file.ntvfs = h;
1349 io->generic.out.create_action = stream_existed?
1350 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1351 io->generic.out.create_time = name->dos.create_time;
1352 io->generic.out.access_time = name->dos.access_time;
1353 io->generic.out.write_time = name->dos.write_time;
1354 io->generic.out.change_time = name->dos.change_time;
1355 io->generic.out.attrib = name->dos.attrib;
1356 io->generic.out.alloc_size = name->dos.alloc_size;
1357 io->generic.out.size = name->st.st_size;
1358 io->generic.out.file_type = FILE_TYPE_DISK;
1359 io->generic.out.ipc_state = 0;
1360 io->generic.out.is_directory = 0;
1362 return NT_STATUS_OK;
1369 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1370 struct ntvfs_request *req, union smb_close *io)
1372 struct pvfs_state *pvfs = ntvfs->private_data;
1373 struct pvfs_file *f;
1374 struct utimbuf unix_times;
1376 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1377 return NT_STATUS_DOS(ERRSRV, ERRerror);
1380 if (io->generic.level != RAW_CLOSE_CLOSE) {
1381 return ntvfs_map_close(ntvfs, req, io);
1384 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1386 return NT_STATUS_INVALID_HANDLE;
1389 if (!null_time(io->close.in.write_time)) {
1390 unix_times.actime = 0;
1391 unix_times.modtime = io->close.in.write_time;
1392 utime(f->handle->name->full_name, &unix_times);
1393 } else if (f->handle->sticky_write_time) {
1394 unix_times.actime = 0;
1395 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1396 utime(f->handle->name->full_name, &unix_times);
1401 return NT_STATUS_OK;
1406 logoff - close all file descriptors open by a vuid
1408 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1409 struct ntvfs_request *req)
1411 struct pvfs_state *pvfs = ntvfs->private_data;
1412 struct pvfs_file *f, *next;
1414 for (f=pvfs->files.list;f;f=next) {
1416 if (f->ntvfs->session_info == req->session_info) {
1421 return NT_STATUS_OK;
1426 exit - close files for the current pid
1428 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1429 struct ntvfs_request *req)
1431 struct pvfs_state *pvfs = ntvfs->private_data;
1432 struct pvfs_file *f, *next;
1434 for (f=pvfs->files.list;f;f=next) {
1436 if (f->ntvfs->session_info == req->session_info &&
1437 f->ntvfs->smbpid == req->smbpid) {
1442 return NT_STATUS_OK;
1447 change the delete on close flag on an already open file
1449 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1450 struct ntvfs_request *req,
1451 struct pvfs_file *f, bool del_on_close)
1453 struct odb_lock *lck;
1456 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1457 return NT_STATUS_CANNOT_DELETE;
1460 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1461 !pvfs_directory_empty(pvfs, f->handle->name)) {
1462 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1466 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1468 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1471 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1473 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1476 status = odb_set_delete_on_close(lck, del_on_close);
1485 determine if a file can be deleted, or if it is prevented by an
1488 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1489 struct ntvfs_request *req,
1490 struct pvfs_filename *name,
1491 struct odb_lock **lckp)
1495 struct odb_lock *lck;
1496 uint32_t share_access;
1497 uint32_t access_mask;
1498 bool delete_on_close;
1500 status = pvfs_locking_key(name, name, &key);
1501 if (!NT_STATUS_IS_OK(status)) {
1502 return NT_STATUS_NO_MEMORY;
1505 lck = odb_lock(req, pvfs->odb_context, &key);
1507 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1508 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1511 share_access = NTCREATEX_SHARE_ACCESS_READ |
1512 NTCREATEX_SHARE_ACCESS_WRITE |
1513 NTCREATEX_SHARE_ACCESS_DELETE;
1514 access_mask = SEC_STD_DELETE;
1515 delete_on_close = true;
1517 status = odb_can_open(lck, name->stream_id,
1518 share_access, access_mask, delete_on_close,
1521 if (NT_STATUS_IS_OK(status)) {
1522 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1526 * if it's a sharing violation or we got no oplock
1527 * only keep the lock if the caller requested access
1530 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1531 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1537 } else if (!NT_STATUS_IS_OK(status)) {
1550 determine if a file can be renamed, or if it is prevented by an
1553 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1554 struct ntvfs_request *req,
1555 struct pvfs_filename *name,
1556 struct odb_lock **lckp)
1560 struct odb_lock *lck;
1561 uint32_t share_access;
1562 uint32_t access_mask;
1563 bool delete_on_close;
1565 status = pvfs_locking_key(name, name, &key);
1566 if (!NT_STATUS_IS_OK(status)) {
1567 return NT_STATUS_NO_MEMORY;
1570 lck = odb_lock(req, pvfs->odb_context, &key);
1572 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1573 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1576 share_access = NTCREATEX_SHARE_ACCESS_READ |
1577 NTCREATEX_SHARE_ACCESS_WRITE;
1578 access_mask = SEC_STD_DELETE;
1579 delete_on_close = false;
1581 status = odb_can_open(lck, name->stream_id,
1582 share_access, access_mask, delete_on_close,
1586 * if it's a sharing violation or we got no oplock
1587 * only keep the lock if the caller requested access
1590 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1591 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1597 } else if (!NT_STATUS_IS_OK(status)) {
1610 determine if file meta data can be accessed, or if it is prevented by an
1613 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1614 struct ntvfs_request *req,
1615 struct pvfs_filename *name)
1619 struct odb_lock *lck;
1620 uint32_t share_access;
1621 uint32_t access_mask;
1622 bool delete_on_close;
1624 status = pvfs_locking_key(name, name, &key);
1625 if (!NT_STATUS_IS_OK(status)) {
1626 return NT_STATUS_NO_MEMORY;
1629 lck = odb_lock(req, pvfs->odb_context, &key);
1631 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1632 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1635 share_access = NTCREATEX_SHARE_ACCESS_READ |
1636 NTCREATEX_SHARE_ACCESS_WRITE;
1638 delete_on_close = false;
1640 status = odb_can_open(lck, name->stream_id,
1641 share_access, access_mask, delete_on_close,
1644 if (!NT_STATUS_IS_OK(status)) {
1653 determine if delete on close is set on
1655 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h,
1656 int *open_count, char **path)
1661 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1662 &del_on_close, open_count, path);
1663 if (!NT_STATUS_IS_OK(status)) {
1664 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1668 return del_on_close;