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->sticky_write_time = false;
272 f->handle->open_completed = false;
274 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
275 pvfs_directory_empty(pvfs, f->handle->name)) {
278 del_on_close = false;
282 /* form the lock context used for opendb locking */
283 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
284 if (!NT_STATUS_IS_OK(status)) {
288 /* get a lock on this file before the actual open */
289 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
291 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
293 /* we were supposed to do a blocking lock, so something
295 return NT_STATUS_INTERNAL_DB_CORRUPTION;
298 /* see if we are allowed to open at the same time as existing opens */
299 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
300 share_access, access_mask, del_on_close,
301 io->generic.in.open_disposition,
302 false, OPLOCK_NONE, NULL);
304 if (!NT_STATUS_IS_OK(status)) {
309 f->handle->have_opendb_entry = true;
312 DLIST_ADD(pvfs->files.list, f);
314 /* setup destructors to avoid leaks on abnormal termination */
315 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
316 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
319 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
320 mode_t mode = pvfs_fileperms(pvfs, attrib);
322 if (mkdir(name->full_name, mode) == -1) {
323 return pvfs_map_errno(pvfs,errno);
326 pvfs_xattr_unlink_hook(pvfs, name->full_name);
328 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
329 if (!NT_STATUS_IS_OK(status)) {
333 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
334 if (!NT_STATUS_IS_OK(status)) {
338 /* form the lock context used for opendb locking */
339 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
340 if (!NT_STATUS_IS_OK(status)) {
344 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
346 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
348 /* we were supposed to do a blocking lock, so something
350 return NT_STATUS_INTERNAL_DB_CORRUPTION;
353 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
354 share_access, access_mask, del_on_close,
355 io->generic.in.open_disposition,
356 false, OPLOCK_NONE, NULL);
358 if (!NT_STATUS_IS_OK(status)) {
362 f->handle->have_opendb_entry = true;
364 create_action = NTCREATEX_ACTION_CREATED;
366 notify_trigger(pvfs->notify_context,
368 FILE_NOTIFY_CHANGE_DIR_NAME,
371 create_action = NTCREATEX_ACTION_EXISTED;
375 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
378 /* the open succeeded, keep this handle permanently */
379 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
380 if (!NT_STATUS_IS_OK(status)) {
384 f->handle->open_completed = true;
386 io->generic.out.oplock_level = OPLOCK_NONE;
387 io->generic.out.file.ntvfs = h;
388 io->generic.out.create_action = create_action;
389 io->generic.out.create_time = name->dos.create_time;
390 io->generic.out.access_time = name->dos.access_time;
391 io->generic.out.write_time = name->dos.write_time;
392 io->generic.out.change_time = name->dos.change_time;
393 io->generic.out.attrib = name->dos.attrib;
394 io->generic.out.alloc_size = name->dos.alloc_size;
395 io->generic.out.size = name->st.st_size;
396 io->generic.out.file_type = FILE_TYPE_DISK;
397 io->generic.out.ipc_state = 0;
398 io->generic.out.is_directory = 1;
403 rmdir(name->full_name);
408 destroy a struct pvfs_file_handle
410 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
415 /* the write time is no longer sticky */
416 if (h->sticky_write_time) {
418 status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
419 if (NT_STATUS_IS_OK(status)) {
420 h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
421 pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
425 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
426 h->name->stream_name) {
428 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
429 if (!NT_STATUS_IS_OK(status)) {
430 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
431 h->name->stream_name, h->name->full_name));
436 if (close(h->fd) != 0) {
437 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
438 h->fd, h->name->full_name, strerror(errno)));
443 if (h->name->stream_name == NULL &&
445 pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
448 status = pvfs_xattr_unlink_hook(h->pvfs, path);
449 if (!NT_STATUS_IS_OK(status)) {
450 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
451 path, nt_errstr(status)));
453 if (unlink(path) != 0) {
454 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
455 path, strerror(errno)));
457 notify_trigger(h->pvfs->notify_context,
458 NOTIFY_ACTION_REMOVED,
459 FILE_NOTIFY_CHANGE_FILE_NAME,
466 if (h->have_opendb_entry) {
467 struct odb_lock *lck;
470 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
472 DEBUG(0,("Unable to lock opendb for close\n"));
476 status = odb_close_file(lck, h);
477 if (!NT_STATUS_IS_OK(status)) {
478 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
479 h->name->full_name, nt_errstr(status)));
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;
561 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
562 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
563 return NT_STATUS_CANNOT_DELETE;
566 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
567 NT_STATUS_NOT_OK_RETURN(status);
569 /* check that the parent isn't opened with delete on close set */
570 status = pvfs_resolve_parent(pvfs, req, name, &parent);
571 if (NT_STATUS_IS_OK(status)) {
572 DATA_BLOB locking_key;
573 status = pvfs_locking_key(parent, req, &locking_key);
574 NT_STATUS_NOT_OK_RETURN(status);
575 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key,
576 &del_on_close, NULL, NULL);
577 NT_STATUS_NOT_OK_RETURN(status);
579 return NT_STATUS_DELETE_PENDING;
583 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
589 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
590 NT_STATUS_NOT_OK_RETURN(status);
592 f = talloc(h, struct pvfs_file);
593 NT_STATUS_HAVE_NO_MEMORY(f);
595 f->handle = talloc(f, struct pvfs_file_handle);
596 NT_STATUS_HAVE_NO_MEMORY(f->handle);
598 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
599 mode = pvfs_fileperms(pvfs, attrib);
601 /* create the file */
602 fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
604 return pvfs_map_errno(pvfs, errno);
607 pvfs_xattr_unlink_hook(pvfs, name->full_name);
609 /* if this was a stream create then create the stream as well */
610 if (name->stream_name) {
611 status = pvfs_stream_create(pvfs, name, fd);
612 if (!NT_STATUS_IS_OK(status)) {
618 /* re-resolve the open fd */
619 status = pvfs_resolve_name_fd(pvfs, fd, name);
620 if (!NT_STATUS_IS_OK(status)) {
625 name->dos.attrib = attrib;
626 status = pvfs_dosattrib_save(pvfs, name, fd);
627 if (!NT_STATUS_IS_OK(status)) {
632 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
633 if (!NT_STATUS_IS_OK(status)) {
637 /* form the lock context used for byte range locking and
639 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
640 if (!NT_STATUS_IS_OK(status)) {
644 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
645 if (!NT_STATUS_IS_OK(status)) {
649 /* grab a lock on the open file record */
650 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
652 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
654 /* we were supposed to do a blocking lock, so something
656 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
660 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
663 del_on_close = false;
666 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
667 oplock_level = OPLOCK_NONE;
668 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
669 oplock_level = OPLOCK_BATCH;
670 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
671 oplock_level = OPLOCK_EXCLUSIVE;
674 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
675 share_access, access_mask, del_on_close,
676 io->generic.in.open_disposition,
677 false, oplock_level, &oplock_granted);
679 if (!NT_STATUS_IS_OK(status)) {
680 /* bad news, we must have hit a race - we don't delete the file
681 here as the most likely scenario is that someone else created
682 the file at the same time */
687 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
688 oplock_granted = OPLOCK_BATCH;
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->have_opendb_entry = true;
709 f->handle->sticky_write_time = false;
710 f->handle->open_completed = false;
712 DLIST_ADD(pvfs->files.list, f);
714 /* setup a destructor to avoid file descriptor leaks on
715 abnormal termination */
716 talloc_set_destructor(f, pvfs_fnum_destructor);
717 talloc_set_destructor(f->handle, pvfs_handle_destructor);
719 io->generic.out.oplock_level = oplock_granted;
720 io->generic.out.file.ntvfs = f->ntvfs;
721 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
722 io->generic.out.create_time = name->dos.create_time;
723 io->generic.out.access_time = name->dos.access_time;
724 io->generic.out.write_time = name->dos.write_time;
725 io->generic.out.change_time = name->dos.change_time;
726 io->generic.out.attrib = name->dos.attrib;
727 io->generic.out.alloc_size = name->dos.alloc_size;
728 io->generic.out.size = name->st.st_size;
729 io->generic.out.file_type = FILE_TYPE_DISK;
730 io->generic.out.ipc_state = 0;
731 io->generic.out.is_directory = 0;
733 /* success - keep the file handle */
734 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
735 if (!NT_STATUS_IS_OK(status)) {
739 f->handle->open_completed = true;
741 notify_trigger(pvfs->notify_context,
743 FILE_NOTIFY_CHANGE_FILE_NAME,
750 unlink(name->full_name);
756 state of a pending open retry
758 struct pvfs_open_retry {
759 struct ntvfs_module_context *ntvfs;
760 struct ntvfs_request *req;
762 struct pvfs_wait *wait_handle;
763 DATA_BLOB odb_locking_key;
766 /* destroy a pending open request */
767 static int pvfs_retry_destructor(struct pvfs_open_retry *r)
769 struct pvfs_state *pvfs = r->ntvfs->private_data;
770 if (r->odb_locking_key.data) {
771 struct odb_lock *lck;
772 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
774 odb_remove_pending(lck, r);
784 static void pvfs_open_retry(void *private, enum pvfs_wait_notice reason)
786 struct pvfs_open_retry *r = private;
787 struct ntvfs_module_context *ntvfs = r->ntvfs;
788 struct ntvfs_request *req = r->req;
789 union smb_open *io = r->io;
792 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
793 just a bug in their server, but we better do the same */
794 if (reason == PVFS_WAIT_CANCEL) {
798 talloc_free(r->wait_handle);
800 if (reason == PVFS_WAIT_TIMEOUT) {
801 /* if it timed out, then give the failure
804 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
805 req->async_states->send_fn(req);
809 /* the pending odb entry is already removed. We use a null locking
810 key to indicate this */
811 data_blob_free(&r->odb_locking_key);
814 /* try the open again, which could trigger another retry setup
815 if it wants to, so we have to unmark the async flag so we
816 will know if it does a second async reply */
817 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
819 status = pvfs_open(ntvfs, req, io);
820 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
821 /* the 2nd try also replied async, so we don't send
826 /* re-mark it async, just in case someone up the chain does
828 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
830 /* send the reply up the chain */
831 req->async_states->status = status;
832 req->async_states->send_fn(req);
837 special handling for openx DENY_DOS semantics
839 This function attempts a reference open using an existing handle. If its allowed,
840 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
841 open processing continues.
843 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
844 struct ntvfs_request *req, union smb_open *io,
845 struct pvfs_file *f, struct odb_lock *lck)
847 struct pvfs_state *pvfs = ntvfs->private_data;
848 struct pvfs_file *f2;
849 struct pvfs_filename *name;
852 /* search for an existing open with the right parameters. Note
853 the magic ntcreatex options flag, which is set in the
854 generic mapping code. This might look ugly, but its
855 actually pretty much now w2k does it internally as well.
857 If you look at the BASE-DENYDOS test you will see that a
858 DENY_DOS is a very special case, and in the right
859 circumstances you actually get the _same_ handle back
860 twice, rather than a new handle.
862 for (f2=pvfs->files.list;f2;f2=f2->next) {
864 f2->ntvfs->session_info == req->session_info &&
865 f2->ntvfs->smbpid == req->smbpid &&
866 (f2->handle->create_options &
867 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
868 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
869 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
870 strcasecmp_m(f2->handle->name->original_name,
871 io->generic.in.fname)==0) {
877 return NT_STATUS_SHARING_VIOLATION;
880 /* quite an insane set of semantics ... */
881 if (is_exe_filename(io->generic.in.fname) &&
882 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
883 return NT_STATUS_SHARING_VIOLATION;
887 setup a reference to the existing handle
889 talloc_free(f->handle);
890 f->handle = talloc_reference(f, f2->handle);
894 name = f->handle->name;
896 io->generic.out.oplock_level = OPLOCK_NONE;
897 io->generic.out.file.ntvfs = f->ntvfs;
898 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
899 io->generic.out.create_time = name->dos.create_time;
900 io->generic.out.access_time = name->dos.access_time;
901 io->generic.out.write_time = name->dos.write_time;
902 io->generic.out.change_time = name->dos.change_time;
903 io->generic.out.attrib = name->dos.attrib;
904 io->generic.out.alloc_size = name->dos.alloc_size;
905 io->generic.out.size = name->st.st_size;
906 io->generic.out.file_type = FILE_TYPE_DISK;
907 io->generic.out.ipc_state = 0;
908 io->generic.out.is_directory = 0;
910 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
911 NT_STATUS_NOT_OK_RETURN(status);
919 setup for a open retry after a sharing violation
921 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
922 struct ntvfs_request *req,
925 struct odb_lock *lck)
927 struct pvfs_state *pvfs = ntvfs->private_data;
928 struct pvfs_open_retry *r;
930 struct timeval end_time;
932 if (io->generic.in.create_options &
933 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
934 /* see if we can satisfy the request using the special DENY_DOS
936 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
937 if (NT_STATUS_IS_OK(status)) {
942 r = talloc(req, struct pvfs_open_retry);
944 return NT_STATUS_NO_MEMORY;
950 r->odb_locking_key = data_blob_talloc(r,
951 f->handle->odb_locking_key.data,
952 f->handle->odb_locking_key.length);
954 end_time = timeval_add(&req->statistics.request_time, 0, pvfs->sharing_violation_delay);
956 /* setup a pending lock */
957 status = odb_open_file_pending(lck, r);
958 if (!NT_STATUS_IS_OK(status)) {
965 talloc_set_destructor(r, pvfs_retry_destructor);
967 r->wait_handle = pvfs_wait_message(pvfs, req, MSG_PVFS_RETRY_OPEN, end_time,
969 if (r->wait_handle == NULL) {
970 return NT_STATUS_NO_MEMORY;
973 talloc_steal(pvfs, r);
981 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
982 struct ntvfs_request *req, union smb_open *io)
984 struct pvfs_state *pvfs = ntvfs->private_data;
986 struct pvfs_filename *name;
988 struct ntvfs_handle *h;
991 struct odb_lock *lck;
992 uint32_t create_options;
993 uint32_t share_access;
994 uint32_t access_mask;
996 bool stream_existed, stream_truncate=false;
997 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
999 /* use the generic mapping code to avoid implementing all the
1000 different open calls. */
1001 if (io->generic.level != RAW_OPEN_GENERIC &&
1002 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1003 return ntvfs_map_open(ntvfs, req, io);
1006 /* resolve the cifs name to a posix name */
1007 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1008 PVFS_RESOLVE_STREAMS, &name);
1009 if (!NT_STATUS_IS_OK(status)) {
1013 /* directory opens are handled separately */
1014 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1015 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1016 return pvfs_open_directory(pvfs, req, name, io);
1019 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1020 open doesn't match */
1021 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1023 create_options = io->generic.in.create_options;
1024 share_access = io->generic.in.share_access;
1025 access_mask = io->generic.in.access_mask;
1027 /* certain create options are not allowed */
1028 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1029 !(access_mask & SEC_STD_DELETE)) {
1030 return NT_STATUS_INVALID_PARAMETER;
1035 switch (io->generic.in.open_disposition) {
1036 case NTCREATEX_DISP_SUPERSEDE:
1037 case NTCREATEX_DISP_OVERWRITE_IF:
1038 if (name->stream_name == NULL) {
1041 stream_truncate = true;
1045 case NTCREATEX_DISP_OPEN:
1046 if (!name->stream_exists) {
1047 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1052 case NTCREATEX_DISP_OVERWRITE:
1053 if (!name->stream_exists) {
1054 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1056 if (name->stream_name == NULL) {
1059 stream_truncate = true;
1063 case NTCREATEX_DISP_CREATE:
1064 if (name->stream_exists) {
1065 return NT_STATUS_OBJECT_NAME_COLLISION;
1070 case NTCREATEX_DISP_OPEN_IF:
1075 return NT_STATUS_INVALID_PARAMETER;
1078 /* handle creating a new file separately */
1079 if (!name->exists) {
1080 status = pvfs_create_file(pvfs, req, name, io);
1081 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1085 /* we've hit a race - the file was created during this call */
1086 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1090 /* try re-resolving the name */
1091 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1092 if (!NT_STATUS_IS_OK(status)) {
1095 /* fall through to a normal open */
1098 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1099 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1100 return NT_STATUS_CANNOT_DELETE;
1103 /* check the security descriptor */
1104 status = pvfs_access_check(pvfs, req, name, &access_mask);
1105 if (!NT_STATUS_IS_OK(status)) {
1109 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1110 NT_STATUS_NOT_OK_RETURN(status);
1112 f = talloc(h, struct pvfs_file);
1114 return NT_STATUS_NO_MEMORY;
1117 f->handle = talloc(f, struct pvfs_file_handle);
1118 if (f->handle == NULL) {
1119 return NT_STATUS_NO_MEMORY;
1124 f->pending_list = NULL;
1126 f->share_access = io->generic.in.share_access;
1127 f->access_mask = access_mask;
1128 f->impersonation = io->generic.in.impersonation;
1129 f->notify_buffer = NULL;
1132 f->handle->pvfs = pvfs;
1134 f->handle->name = talloc_steal(f->handle, name);
1135 f->handle->create_options = io->generic.in.create_options;
1136 f->handle->seek_offset = 0;
1137 f->handle->position = 0;
1138 f->handle->mode = 0;
1139 f->handle->have_opendb_entry = false;
1140 f->handle->sticky_write_time = false;
1141 f->handle->open_completed = false;
1143 /* form the lock context used for byte range locking and
1145 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1146 if (!NT_STATUS_IS_OK(status)) {
1150 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1151 if (!NT_STATUS_IS_OK(status)) {
1155 /* get a lock on this file before the actual open */
1156 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1158 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1160 /* we were supposed to do a blocking lock, so something
1162 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1165 DLIST_ADD(pvfs->files.list, f);
1167 /* setup a destructor to avoid file descriptor leaks on
1168 abnormal termination */
1169 talloc_set_destructor(f, pvfs_fnum_destructor);
1170 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1173 * Only SMB2 takes care of the delete_on_close,
1176 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1177 req->ctx->protocol == PROTOCOL_SMB2) {
1178 del_on_close = true;
1180 del_on_close = false;
1183 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1184 oplock_level = OPLOCK_NONE;
1185 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1186 oplock_level = OPLOCK_BATCH;
1187 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1188 oplock_level = OPLOCK_EXCLUSIVE;
1191 /* see if we are allowed to open at the same time as existing opens */
1192 status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
1193 share_access, access_mask, del_on_close,
1194 io->generic.in.open_disposition,
1195 false, oplock_level, &oplock_granted);
1197 /* on a sharing violation we need to retry when the file is closed by
1198 the other user, or after 1 second */
1199 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) &&
1200 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1201 return pvfs_open_setup_retry(ntvfs, req, io, f, lck);
1204 if (!NT_STATUS_IS_OK(status)) {
1209 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1210 oplock_granted = OPLOCK_BATCH;
1213 f->handle->have_opendb_entry = true;
1215 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1221 /* do the actual open */
1222 fd = open(f->handle->name->full_name, flags);
1225 return pvfs_map_errno(f->pvfs, errno);
1230 stream_existed = name->stream_exists;
1232 /* if this was a stream create then create the stream as well */
1233 if (!name->stream_exists) {
1234 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1235 if (!NT_STATUS_IS_OK(status)) {
1239 if (stream_truncate) {
1240 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1241 if (!NT_STATUS_IS_OK(status)) {
1248 /* re-resolve the open fd */
1249 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1250 if (!NT_STATUS_IS_OK(status)) {
1255 if (f->handle->name->stream_id == 0 &&
1256 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1257 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1258 /* for overwrite we need to replace file permissions */
1259 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1260 mode_t mode = pvfs_fileperms(pvfs, attrib);
1261 if (fchmod(fd, mode) == -1) {
1263 return pvfs_map_errno(pvfs, errno);
1265 name->dos.attrib = attrib;
1266 status = pvfs_dosattrib_save(pvfs, name, fd);
1267 if (!NT_STATUS_IS_OK(status)) {
1275 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1276 NT_STATUS_NOT_OK_RETURN(status);
1278 /* mark the open as having completed fully, so delete on close
1280 f->handle->open_completed = true;
1282 io->generic.out.oplock_level = oplock_granted;
1283 io->generic.out.file.ntvfs = h;
1284 io->generic.out.create_action = stream_existed?
1285 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1286 io->generic.out.create_time = name->dos.create_time;
1287 io->generic.out.access_time = name->dos.access_time;
1288 io->generic.out.write_time = name->dos.write_time;
1289 io->generic.out.change_time = name->dos.change_time;
1290 io->generic.out.attrib = name->dos.attrib;
1291 io->generic.out.alloc_size = name->dos.alloc_size;
1292 io->generic.out.size = name->st.st_size;
1293 io->generic.out.file_type = FILE_TYPE_DISK;
1294 io->generic.out.ipc_state = 0;
1295 io->generic.out.is_directory = 0;
1297 return NT_STATUS_OK;
1304 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1305 struct ntvfs_request *req, union smb_close *io)
1307 struct pvfs_state *pvfs = ntvfs->private_data;
1308 struct pvfs_file *f;
1309 struct utimbuf unix_times;
1311 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1312 return NT_STATUS_DOS(ERRSRV, ERRerror);
1315 if (io->generic.level != RAW_CLOSE_CLOSE) {
1316 return ntvfs_map_close(ntvfs, req, io);
1319 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1321 return NT_STATUS_INVALID_HANDLE;
1324 if (!null_time(io->close.in.write_time)) {
1325 unix_times.actime = 0;
1326 unix_times.modtime = io->close.in.write_time;
1327 utime(f->handle->name->full_name, &unix_times);
1328 } else if (f->handle->sticky_write_time) {
1329 unix_times.actime = 0;
1330 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1331 utime(f->handle->name->full_name, &unix_times);
1336 return NT_STATUS_OK;
1341 logoff - close all file descriptors open by a vuid
1343 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1344 struct ntvfs_request *req)
1346 struct pvfs_state *pvfs = ntvfs->private_data;
1347 struct pvfs_file *f, *next;
1349 for (f=pvfs->files.list;f;f=next) {
1351 if (f->ntvfs->session_info == req->session_info) {
1356 return NT_STATUS_OK;
1361 exit - close files for the current pid
1363 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1364 struct ntvfs_request *req)
1366 struct pvfs_state *pvfs = ntvfs->private_data;
1367 struct pvfs_file *f, *next;
1369 for (f=pvfs->files.list;f;f=next) {
1371 if (f->ntvfs->session_info == req->session_info &&
1372 f->ntvfs->smbpid == req->smbpid) {
1377 return NT_STATUS_OK;
1382 change the delete on close flag on an already open file
1384 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1385 struct ntvfs_request *req,
1386 struct pvfs_file *f, bool del_on_close)
1388 struct odb_lock *lck;
1391 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1392 return NT_STATUS_CANNOT_DELETE;
1395 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1396 !pvfs_directory_empty(pvfs, f->handle->name)) {
1397 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1401 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1403 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1406 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1408 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1411 status = odb_set_delete_on_close(lck, del_on_close);
1420 determine if a file can be deleted, or if it is prevented by an
1423 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1424 struct ntvfs_request *req,
1425 struct pvfs_filename *name,
1426 struct odb_lock **lckp)
1430 struct odb_lock *lck;
1431 uint32_t share_access;
1432 uint32_t access_mask;
1433 bool delete_on_close;
1435 status = pvfs_locking_key(name, name, &key);
1436 if (!NT_STATUS_IS_OK(status)) {
1437 return NT_STATUS_NO_MEMORY;
1440 lck = odb_lock(req, pvfs->odb_context, &key);
1442 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1443 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1446 share_access = NTCREATEX_SHARE_ACCESS_READ |
1447 NTCREATEX_SHARE_ACCESS_WRITE |
1448 NTCREATEX_SHARE_ACCESS_DELETE;
1449 access_mask = SEC_STD_DELETE;
1450 delete_on_close = true;
1452 status = odb_can_open(lck, name->stream_id,
1453 share_access, access_mask, delete_on_close,
1456 if (NT_STATUS_IS_OK(status)) {
1457 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1461 * if it's a sharing violation or we got no oplock
1462 * only keep the lock if the caller requested access
1465 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1466 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1472 } else if (!NT_STATUS_IS_OK(status)) {
1485 determine if a file can be renamed, or if it is prevented by an
1488 NTSTATUS pvfs_can_rename(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_stat\n"));
1508 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1511 share_access = NTCREATEX_SHARE_ACCESS_READ |
1512 NTCREATEX_SHARE_ACCESS_WRITE;
1513 access_mask = SEC_STD_DELETE;
1514 delete_on_close = false;
1516 status = odb_can_open(lck, name->stream_id,
1517 share_access, access_mask, delete_on_close,
1521 * if it's a sharing violation or we got no oplock
1522 * only keep the lock if the caller requested access
1525 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1526 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1532 } else if (!NT_STATUS_IS_OK(status)) {
1545 determine if file meta data can be accessed, or if it is prevented by an
1548 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1549 struct ntvfs_request *req,
1550 struct pvfs_filename *name)
1554 struct odb_lock *lck;
1555 uint32_t share_access;
1556 uint32_t access_mask;
1557 bool delete_on_close;
1559 status = pvfs_locking_key(name, name, &key);
1560 if (!NT_STATUS_IS_OK(status)) {
1561 return NT_STATUS_NO_MEMORY;
1564 lck = odb_lock(req, pvfs->odb_context, &key);
1566 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1567 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1570 share_access = NTCREATEX_SHARE_ACCESS_READ |
1571 NTCREATEX_SHARE_ACCESS_WRITE;
1573 delete_on_close = false;
1575 status = odb_can_open(lck, name->stream_id,
1576 share_access, access_mask, delete_on_close,
1579 if (!NT_STATUS_IS_OK(status)) {
1588 determine if delete on close is set on
1590 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h,
1591 int *open_count, char **path)
1596 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1597 &del_on_close, open_count, path);
1598 if (!NT_STATUS_IS_OK(status)) {
1599 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1603 return del_on_close;