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, f->handle->name->stream_id,
300 share_access, access_mask, del_on_close,
301 name->full_name, OPLOCK_NONE, NULL);
303 if (!NT_STATUS_IS_OK(status)) {
308 f->handle->have_opendb_entry = true;
311 DLIST_ADD(pvfs->files.list, f);
313 /* setup destructors to avoid leaks on abnormal termination */
314 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
315 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
318 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
319 mode_t mode = pvfs_fileperms(pvfs, attrib);
321 if (mkdir(name->full_name, mode) == -1) {
322 return pvfs_map_errno(pvfs,errno);
325 pvfs_xattr_unlink_hook(pvfs, name->full_name);
327 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
328 if (!NT_STATUS_IS_OK(status)) {
332 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
333 if (!NT_STATUS_IS_OK(status)) {
337 /* form the lock context used for opendb locking */
338 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
339 if (!NT_STATUS_IS_OK(status)) {
343 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
345 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
347 /* we were supposed to do a blocking lock, so something
349 return NT_STATUS_INTERNAL_DB_CORRUPTION;
352 status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
353 share_access, access_mask, del_on_close,
354 name->full_name, OPLOCK_NONE, NULL);
356 if (!NT_STATUS_IS_OK(status)) {
360 f->handle->have_opendb_entry = true;
362 create_action = NTCREATEX_ACTION_CREATED;
364 notify_trigger(pvfs->notify_context,
366 FILE_NOTIFY_CHANGE_DIR_NAME,
369 create_action = NTCREATEX_ACTION_EXISTED;
373 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
376 /* the open succeeded, keep this handle permanently */
377 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
378 if (!NT_STATUS_IS_OK(status)) {
382 f->handle->open_completed = true;
384 io->generic.out.oplock_level = OPLOCK_NONE;
385 io->generic.out.file.ntvfs = h;
386 io->generic.out.create_action = create_action;
387 io->generic.out.create_time = name->dos.create_time;
388 io->generic.out.access_time = name->dos.access_time;
389 io->generic.out.write_time = name->dos.write_time;
390 io->generic.out.change_time = name->dos.change_time;
391 io->generic.out.attrib = name->dos.attrib;
392 io->generic.out.alloc_size = name->dos.alloc_size;
393 io->generic.out.size = name->st.st_size;
394 io->generic.out.file_type = FILE_TYPE_DISK;
395 io->generic.out.ipc_state = 0;
396 io->generic.out.is_directory = 1;
401 rmdir(name->full_name);
406 destroy a struct pvfs_file_handle
408 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
413 /* the write time is no longer sticky */
414 if (h->sticky_write_time) {
416 status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
417 if (NT_STATUS_IS_OK(status)) {
418 h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
419 pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
423 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
424 h->name->stream_name) {
426 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
427 if (!NT_STATUS_IS_OK(status)) {
428 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
429 h->name->stream_name, h->name->full_name));
434 if (close(h->fd) != 0) {
435 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
436 h->fd, h->name->full_name, strerror(errno)));
441 if (h->name->stream_name == NULL &&
443 pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
446 status = pvfs_xattr_unlink_hook(h->pvfs, path);
447 if (!NT_STATUS_IS_OK(status)) {
448 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
449 path, nt_errstr(status)));
451 if (unlink(path) != 0) {
452 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
453 path, strerror(errno)));
455 notify_trigger(h->pvfs->notify_context,
456 NOTIFY_ACTION_REMOVED,
457 FILE_NOTIFY_CHANGE_FILE_NAME,
464 if (h->have_opendb_entry) {
465 struct odb_lock *lck;
468 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
470 DEBUG(0,("Unable to lock opendb for close\n"));
474 status = odb_close_file(lck, h);
475 if (!NT_STATUS_IS_OK(status)) {
476 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
477 h->name->full_name, nt_errstr(status)));
488 destroy a struct pvfs_file
490 static int pvfs_fnum_destructor(struct pvfs_file *f)
492 DLIST_REMOVE(f->pvfs->files.list, f);
493 pvfs_lock_close(f->pvfs, f);
494 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
501 form the lock context used for byte range locking. This is separate
502 from the locking key used for opendb locking as it needs to take
503 account of file streams (each stream is a separate byte range
506 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
507 struct pvfs_filename *name,
508 struct ntvfs_handle *ntvfs,
509 struct brl_handle **_h)
511 DATA_BLOB odb_key, key;
513 struct brl_handle *h;
515 status = pvfs_locking_key(name, mem_ctx, &odb_key);
516 NT_STATUS_NOT_OK_RETURN(status);
518 if (name->stream_name == NULL) {
521 key = data_blob_talloc(mem_ctx, NULL,
522 odb_key.length + strlen(name->stream_name) + 1);
523 NT_STATUS_HAVE_NO_MEMORY(key.data);
524 memcpy(key.data, odb_key.data, odb_key.length);
525 memcpy(key.data + odb_key.length,
526 name->stream_name, strlen(name->stream_name) + 1);
527 data_blob_free(&odb_key);
530 h = brl_create_handle(mem_ctx, ntvfs, &key);
531 NT_STATUS_HAVE_NO_MEMORY(h);
540 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
541 struct ntvfs_request *req,
542 struct pvfs_filename *name,
547 struct ntvfs_handle *h;
549 struct odb_lock *lck;
550 uint32_t create_options = io->generic.in.create_options;
551 uint32_t share_access = io->generic.in.share_access;
552 uint32_t access_mask = io->generic.in.access_mask;
556 struct pvfs_filename *parent;
557 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
559 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
560 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
561 return NT_STATUS_CANNOT_DELETE;
564 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
565 NT_STATUS_NOT_OK_RETURN(status);
567 /* check that the parent isn't opened with delete on close set */
568 status = pvfs_resolve_parent(pvfs, req, name, &parent);
569 if (NT_STATUS_IS_OK(status)) {
570 DATA_BLOB locking_key;
571 status = pvfs_locking_key(parent, req, &locking_key);
572 NT_STATUS_NOT_OK_RETURN(status);
573 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key,
574 &del_on_close, NULL, NULL);
575 NT_STATUS_NOT_OK_RETURN(status);
577 return NT_STATUS_DELETE_PENDING;
581 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
587 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
588 NT_STATUS_NOT_OK_RETURN(status);
590 f = talloc(h, struct pvfs_file);
591 NT_STATUS_HAVE_NO_MEMORY(f);
593 f->handle = talloc(f, struct pvfs_file_handle);
594 NT_STATUS_HAVE_NO_MEMORY(f->handle);
596 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
597 mode = pvfs_fileperms(pvfs, attrib);
599 /* create the file */
600 fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
602 return pvfs_map_errno(pvfs, errno);
605 pvfs_xattr_unlink_hook(pvfs, name->full_name);
607 /* if this was a stream create then create the stream as well */
608 if (name->stream_name) {
609 status = pvfs_stream_create(pvfs, name, fd);
610 if (!NT_STATUS_IS_OK(status)) {
616 /* re-resolve the open fd */
617 status = pvfs_resolve_name_fd(pvfs, fd, name);
618 if (!NT_STATUS_IS_OK(status)) {
623 name->dos.attrib = attrib;
624 status = pvfs_dosattrib_save(pvfs, name, fd);
625 if (!NT_STATUS_IS_OK(status)) {
630 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
631 if (!NT_STATUS_IS_OK(status)) {
635 /* form the lock context used for byte range locking and
637 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
638 if (!NT_STATUS_IS_OK(status)) {
642 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
643 if (!NT_STATUS_IS_OK(status)) {
647 /* grab a lock on the open file record */
648 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
650 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
652 /* we were supposed to do a blocking lock, so something
654 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
658 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
661 del_on_close = false;
664 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
665 oplock_level = OPLOCK_NONE;
666 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
667 oplock_level = OPLOCK_BATCH;
668 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
669 oplock_level = OPLOCK_EXCLUSIVE;
672 status = odb_open_file(lck, f->handle, name->stream_id,
673 share_access, access_mask, del_on_close,
674 name->full_name, oplock_level, &oplock_granted);
676 if (!NT_STATUS_IS_OK(status)) {
677 /* bad news, we must have hit a race - we don't delete the file
678 here as the most likely scenario is that someone else created
679 the file at the same time */
684 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
685 oplock_granted = OPLOCK_BATCH;
690 f->pending_list = NULL;
692 f->share_access = io->generic.in.share_access;
693 f->access_mask = access_mask;
694 f->impersonation = io->generic.in.impersonation;
695 f->notify_buffer = NULL;
698 f->handle->pvfs = pvfs;
699 f->handle->name = talloc_steal(f->handle, name);
701 f->handle->create_options = io->generic.in.create_options;
702 f->handle->seek_offset = 0;
703 f->handle->position = 0;
705 f->handle->have_opendb_entry = true;
706 f->handle->sticky_write_time = false;
707 f->handle->open_completed = false;
709 DLIST_ADD(pvfs->files.list, f);
711 /* setup a destructor to avoid file descriptor leaks on
712 abnormal termination */
713 talloc_set_destructor(f, pvfs_fnum_destructor);
714 talloc_set_destructor(f->handle, pvfs_handle_destructor);
716 io->generic.out.oplock_level = oplock_granted;
717 io->generic.out.file.ntvfs = f->ntvfs;
718 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
719 io->generic.out.create_time = name->dos.create_time;
720 io->generic.out.access_time = name->dos.access_time;
721 io->generic.out.write_time = name->dos.write_time;
722 io->generic.out.change_time = name->dos.change_time;
723 io->generic.out.attrib = name->dos.attrib;
724 io->generic.out.alloc_size = name->dos.alloc_size;
725 io->generic.out.size = name->st.st_size;
726 io->generic.out.file_type = FILE_TYPE_DISK;
727 io->generic.out.ipc_state = 0;
728 io->generic.out.is_directory = 0;
730 /* success - keep the file handle */
731 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
732 if (!NT_STATUS_IS_OK(status)) {
736 f->handle->open_completed = true;
738 notify_trigger(pvfs->notify_context,
740 FILE_NOTIFY_CHANGE_FILE_NAME,
747 unlink(name->full_name);
753 state of a pending open retry
755 struct pvfs_open_retry {
756 struct ntvfs_module_context *ntvfs;
757 struct ntvfs_request *req;
760 DATA_BLOB odb_locking_key;
763 /* destroy a pending open request */
764 static int pvfs_retry_destructor(struct pvfs_open_retry *r)
766 struct pvfs_state *pvfs = r->ntvfs->private_data;
767 if (r->odb_locking_key.data) {
768 struct odb_lock *lck;
769 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
771 odb_remove_pending(lck, r);
781 static void pvfs_open_retry(void *private, enum pvfs_wait_notice reason)
783 struct pvfs_open_retry *r = private;
784 struct ntvfs_module_context *ntvfs = r->ntvfs;
785 struct ntvfs_request *req = r->req;
786 union smb_open *io = r->io;
789 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
790 just a bug in their server, but we better do the same */
791 if (reason == PVFS_WAIT_CANCEL) {
795 talloc_free(r->wait_handle);
797 if (reason == PVFS_WAIT_TIMEOUT) {
798 /* if it timed out, then give the failure
801 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
802 req->async_states->send_fn(req);
806 /* the pending odb entry is already removed. We use a null locking
807 key to indicate this */
808 data_blob_free(&r->odb_locking_key);
811 /* try the open again, which could trigger another retry setup
812 if it wants to, so we have to unmark the async flag so we
813 will know if it does a second async reply */
814 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
816 status = pvfs_open(ntvfs, req, io);
817 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
818 /* the 2nd try also replied async, so we don't send
823 /* re-mark it async, just in case someone up the chain does
825 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
827 /* send the reply up the chain */
828 req->async_states->status = status;
829 req->async_states->send_fn(req);
834 special handling for openx DENY_DOS semantics
836 This function attempts a reference open using an existing handle. If its allowed,
837 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
838 open processing continues.
840 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
841 struct ntvfs_request *req, union smb_open *io,
842 struct pvfs_file *f, struct odb_lock *lck)
844 struct pvfs_state *pvfs = ntvfs->private_data;
845 struct pvfs_file *f2;
846 struct pvfs_filename *name;
849 /* search for an existing open with the right parameters. Note
850 the magic ntcreatex options flag, which is set in the
851 generic mapping code. This might look ugly, but its
852 actually pretty much now w2k does it internally as well.
854 If you look at the BASE-DENYDOS test you will see that a
855 DENY_DOS is a very special case, and in the right
856 circumstances you actually get the _same_ handle back
857 twice, rather than a new handle.
859 for (f2=pvfs->files.list;f2;f2=f2->next) {
861 f2->ntvfs->session_info == req->session_info &&
862 f2->ntvfs->smbpid == req->smbpid &&
863 (f2->handle->create_options &
864 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
865 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
866 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
867 strcasecmp_m(f2->handle->name->original_name,
868 io->generic.in.fname)==0) {
874 return NT_STATUS_SHARING_VIOLATION;
877 /* quite an insane set of semantics ... */
878 if (is_exe_filename(io->generic.in.fname) &&
879 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
880 return NT_STATUS_SHARING_VIOLATION;
884 setup a reference to the existing handle
886 talloc_free(f->handle);
887 f->handle = talloc_reference(f, f2->handle);
891 name = f->handle->name;
893 io->generic.out.oplock_level = OPLOCK_NONE;
894 io->generic.out.file.ntvfs = f->ntvfs;
895 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
896 io->generic.out.create_time = name->dos.create_time;
897 io->generic.out.access_time = name->dos.access_time;
898 io->generic.out.write_time = name->dos.write_time;
899 io->generic.out.change_time = name->dos.change_time;
900 io->generic.out.attrib = name->dos.attrib;
901 io->generic.out.alloc_size = name->dos.alloc_size;
902 io->generic.out.size = name->st.st_size;
903 io->generic.out.file_type = FILE_TYPE_DISK;
904 io->generic.out.ipc_state = 0;
905 io->generic.out.is_directory = 0;
907 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
908 NT_STATUS_NOT_OK_RETURN(status);
916 setup for a open retry after a sharing violation
918 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
919 struct ntvfs_request *req,
922 struct odb_lock *lck)
924 struct pvfs_state *pvfs = ntvfs->private_data;
925 struct pvfs_open_retry *r;
927 struct timeval end_time;
929 if (io->generic.in.create_options &
930 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
931 /* see if we can satisfy the request using the special DENY_DOS
933 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
934 if (NT_STATUS_IS_OK(status)) {
939 r = talloc(req, struct pvfs_open_retry);
941 return NT_STATUS_NO_MEMORY;
947 r->odb_locking_key = data_blob_talloc(r,
948 f->handle->odb_locking_key.data,
949 f->handle->odb_locking_key.length);
951 end_time = timeval_add(&req->statistics.request_time, 0, pvfs->sharing_violation_delay);
953 /* setup a pending lock */
954 status = odb_open_file_pending(lck, r);
955 if (!NT_STATUS_IS_OK(status)) {
962 talloc_set_destructor(r, pvfs_retry_destructor);
964 r->wait_handle = pvfs_wait_message(pvfs, req, MSG_PVFS_RETRY_OPEN, end_time,
966 if (r->wait_handle == NULL) {
967 return NT_STATUS_NO_MEMORY;
970 talloc_steal(pvfs, r);
978 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
979 struct ntvfs_request *req, union smb_open *io)
981 struct pvfs_state *pvfs = ntvfs->private_data;
983 struct pvfs_filename *name;
985 struct ntvfs_handle *h;
988 struct odb_lock *lck;
989 uint32_t create_options;
990 uint32_t share_access;
991 uint32_t access_mask;
993 bool stream_existed, stream_truncate=false;
994 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
996 /* use the generic mapping code to avoid implementing all the
997 different open calls. */
998 if (io->generic.level != RAW_OPEN_GENERIC &&
999 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1000 return ntvfs_map_open(ntvfs, req, io);
1003 /* resolve the cifs name to a posix name */
1004 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1005 PVFS_RESOLVE_STREAMS, &name);
1006 if (!NT_STATUS_IS_OK(status)) {
1010 /* directory opens are handled separately */
1011 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1012 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1013 return pvfs_open_directory(pvfs, req, name, io);
1016 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1017 open doesn't match */
1018 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1020 create_options = io->generic.in.create_options;
1021 share_access = io->generic.in.share_access;
1022 access_mask = io->generic.in.access_mask;
1024 /* certain create options are not allowed */
1025 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1026 !(access_mask & SEC_STD_DELETE)) {
1027 return NT_STATUS_INVALID_PARAMETER;
1032 switch (io->generic.in.open_disposition) {
1033 case NTCREATEX_DISP_SUPERSEDE:
1034 case NTCREATEX_DISP_OVERWRITE_IF:
1035 if (name->stream_name == NULL) {
1038 stream_truncate = true;
1042 case NTCREATEX_DISP_OPEN:
1043 if (!name->stream_exists) {
1044 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1049 case NTCREATEX_DISP_OVERWRITE:
1050 if (!name->stream_exists) {
1051 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1053 if (name->stream_name == NULL) {
1056 stream_truncate = true;
1060 case NTCREATEX_DISP_CREATE:
1061 if (name->stream_exists) {
1062 return NT_STATUS_OBJECT_NAME_COLLISION;
1067 case NTCREATEX_DISP_OPEN_IF:
1072 return NT_STATUS_INVALID_PARAMETER;
1075 /* handle creating a new file separately */
1076 if (!name->exists) {
1077 status = pvfs_create_file(pvfs, req, name, io);
1078 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1082 /* we've hit a race - the file was created during this call */
1083 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1087 /* try re-resolving the name */
1088 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1089 if (!NT_STATUS_IS_OK(status)) {
1092 /* fall through to a normal open */
1095 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1096 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1097 return NT_STATUS_CANNOT_DELETE;
1100 /* check the security descriptor */
1101 status = pvfs_access_check(pvfs, req, name, &access_mask);
1102 if (!NT_STATUS_IS_OK(status)) {
1106 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1107 NT_STATUS_NOT_OK_RETURN(status);
1109 f = talloc(h, struct pvfs_file);
1111 return NT_STATUS_NO_MEMORY;
1114 f->handle = talloc(f, struct pvfs_file_handle);
1115 if (f->handle == NULL) {
1116 return NT_STATUS_NO_MEMORY;
1121 f->pending_list = NULL;
1123 f->share_access = io->generic.in.share_access;
1124 f->access_mask = access_mask;
1125 f->impersonation = io->generic.in.impersonation;
1126 f->notify_buffer = NULL;
1129 f->handle->pvfs = pvfs;
1131 f->handle->name = talloc_steal(f->handle, name);
1132 f->handle->create_options = io->generic.in.create_options;
1133 f->handle->seek_offset = 0;
1134 f->handle->position = 0;
1135 f->handle->mode = 0;
1136 f->handle->have_opendb_entry = false;
1137 f->handle->sticky_write_time = false;
1138 f->handle->open_completed = false;
1140 /* form the lock context used for byte range locking and
1142 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1143 if (!NT_STATUS_IS_OK(status)) {
1147 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1148 if (!NT_STATUS_IS_OK(status)) {
1152 /* get a lock on this file before the actual open */
1153 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1155 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1157 /* we were supposed to do a blocking lock, so something
1159 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1162 DLIST_ADD(pvfs->files.list, f);
1164 /* setup a destructor to avoid file descriptor leaks on
1165 abnormal termination */
1166 talloc_set_destructor(f, pvfs_fnum_destructor);
1167 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1170 * Only SMB2 takes care of the delete_on_close,
1173 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1174 req->ctx->protocol == PROTOCOL_SMB2) {
1175 del_on_close = true;
1177 del_on_close = false;
1180 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1181 oplock_level = OPLOCK_NONE;
1182 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1183 oplock_level = OPLOCK_BATCH;
1184 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1185 oplock_level = OPLOCK_EXCLUSIVE;
1188 /* see if we are allowed to open at the same time as existing opens */
1189 status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
1190 share_access, access_mask, del_on_close,
1191 name->full_name, oplock_level, &oplock_granted);
1193 /* on a sharing violation we need to retry when the file is closed by
1194 the other user, or after 1 second */
1195 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) &&
1196 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1197 return pvfs_open_setup_retry(ntvfs, req, io, f, lck);
1200 if (!NT_STATUS_IS_OK(status)) {
1205 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1206 oplock_granted = OPLOCK_BATCH;
1209 f->handle->have_opendb_entry = true;
1211 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1217 /* do the actual open */
1218 fd = open(f->handle->name->full_name, flags);
1221 return pvfs_map_errno(f->pvfs, errno);
1226 stream_existed = name->stream_exists;
1228 /* if this was a stream create then create the stream as well */
1229 if (!name->stream_exists) {
1230 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1231 if (!NT_STATUS_IS_OK(status)) {
1235 if (stream_truncate) {
1236 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1237 if (!NT_STATUS_IS_OK(status)) {
1244 /* re-resolve the open fd */
1245 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1246 if (!NT_STATUS_IS_OK(status)) {
1251 if (f->handle->name->stream_id == 0 &&
1252 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1253 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1254 /* for overwrite we need to replace file permissions */
1255 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1256 mode_t mode = pvfs_fileperms(pvfs, attrib);
1257 if (fchmod(fd, mode) == -1) {
1259 return pvfs_map_errno(pvfs, errno);
1261 name->dos.attrib = attrib;
1262 status = pvfs_dosattrib_save(pvfs, name, fd);
1263 if (!NT_STATUS_IS_OK(status)) {
1271 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1272 NT_STATUS_NOT_OK_RETURN(status);
1274 /* mark the open as having completed fully, so delete on close
1276 f->handle->open_completed = true;
1278 io->generic.out.oplock_level = oplock_granted;
1279 io->generic.out.file.ntvfs = h;
1280 io->generic.out.create_action = stream_existed?
1281 NTCREATEX_ACTION_EXISTED:NTCREATEX_ACTION_CREATED;
1282 io->generic.out.create_time = name->dos.create_time;
1283 io->generic.out.access_time = name->dos.access_time;
1284 io->generic.out.write_time = name->dos.write_time;
1285 io->generic.out.change_time = name->dos.change_time;
1286 io->generic.out.attrib = name->dos.attrib;
1287 io->generic.out.alloc_size = name->dos.alloc_size;
1288 io->generic.out.size = name->st.st_size;
1289 io->generic.out.file_type = FILE_TYPE_DISK;
1290 io->generic.out.ipc_state = 0;
1291 io->generic.out.is_directory = 0;
1293 return NT_STATUS_OK;
1300 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1301 struct ntvfs_request *req, union smb_close *io)
1303 struct pvfs_state *pvfs = ntvfs->private_data;
1304 struct pvfs_file *f;
1305 struct utimbuf unix_times;
1307 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1308 return NT_STATUS_DOS(ERRSRV, ERRerror);
1311 if (io->generic.level != RAW_CLOSE_CLOSE) {
1312 return ntvfs_map_close(ntvfs, req, io);
1315 f = pvfs_find_fd(pvfs, req, io->close.in.file.ntvfs);
1317 return NT_STATUS_INVALID_HANDLE;
1320 if (!null_time(io->close.in.write_time)) {
1321 unix_times.actime = 0;
1322 unix_times.modtime = io->close.in.write_time;
1323 utime(f->handle->name->full_name, &unix_times);
1324 } else if (f->handle->sticky_write_time) {
1325 unix_times.actime = 0;
1326 unix_times.modtime = nt_time_to_unix(f->handle->name->dos.write_time);
1327 utime(f->handle->name->full_name, &unix_times);
1332 return NT_STATUS_OK;
1337 logoff - close all file descriptors open by a vuid
1339 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1340 struct ntvfs_request *req)
1342 struct pvfs_state *pvfs = ntvfs->private_data;
1343 struct pvfs_file *f, *next;
1345 for (f=pvfs->files.list;f;f=next) {
1347 if (f->ntvfs->session_info == req->session_info) {
1352 return NT_STATUS_OK;
1357 exit - close files for the current pid
1359 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1360 struct ntvfs_request *req)
1362 struct pvfs_state *pvfs = ntvfs->private_data;
1363 struct pvfs_file *f, *next;
1365 for (f=pvfs->files.list;f;f=next) {
1367 if (f->ntvfs->session_info == req->session_info &&
1368 f->ntvfs->smbpid == req->smbpid) {
1373 return NT_STATUS_OK;
1378 change the delete on close flag on an already open file
1380 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1381 struct ntvfs_request *req,
1382 struct pvfs_file *f, bool del_on_close)
1384 struct odb_lock *lck;
1387 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1388 return NT_STATUS_CANNOT_DELETE;
1391 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1392 !pvfs_directory_empty(pvfs, f->handle->name)) {
1393 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1397 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1399 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1402 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1404 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1407 status = odb_set_delete_on_close(lck, del_on_close);
1416 determine if a file can be deleted, or if it is prevented by an
1419 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1420 struct ntvfs_request *req,
1421 struct pvfs_filename *name,
1422 struct odb_lock **lckp)
1426 struct odb_lock *lck;
1428 status = pvfs_locking_key(name, name, &key);
1429 if (!NT_STATUS_IS_OK(status)) {
1430 return NT_STATUS_NO_MEMORY;
1433 lck = odb_lock(req, pvfs->odb_context, &key);
1435 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1436 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1439 status = odb_can_open(lck,
1440 NTCREATEX_SHARE_ACCESS_READ |
1441 NTCREATEX_SHARE_ACCESS_WRITE |
1442 NTCREATEX_SHARE_ACCESS_DELETE,
1443 NTCREATEX_OPTIONS_DELETE_ON_CLOSE,
1446 if (NT_STATUS_IS_OK(status)) {
1447 status = pvfs_access_check_simple(pvfs, req, name, SEC_STD_DELETE);
1450 if (!NT_STATUS_IS_OK(status)) {
1453 } else if (lckp != NULL) {
1461 determine if a file can be renamed, or if it is prevented by an
1464 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1465 struct ntvfs_request *req,
1466 struct pvfs_filename *name,
1467 struct odb_lock **lckp)
1471 struct odb_lock *lck;
1473 status = pvfs_locking_key(name, name, &key);
1474 if (!NT_STATUS_IS_OK(status)) {
1475 return NT_STATUS_NO_MEMORY;
1478 lck = odb_lock(req, pvfs->odb_context, &key);
1480 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1481 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1484 status = odb_can_open(lck,
1485 NTCREATEX_SHARE_ACCESS_READ |
1486 NTCREATEX_SHARE_ACCESS_WRITE,
1490 if (!NT_STATUS_IS_OK(status)) {
1493 } else if (lckp != NULL) {
1501 determine if file meta data can be accessed, or if it is prevented by an
1504 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1505 struct ntvfs_request *req,
1506 struct pvfs_filename *name)
1510 struct odb_lock *lck;
1512 status = pvfs_locking_key(name, name, &key);
1513 if (!NT_STATUS_IS_OK(status)) {
1514 return NT_STATUS_NO_MEMORY;
1517 lck = odb_lock(req, pvfs->odb_context, &key);
1519 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1520 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1523 status = odb_can_open(lck,
1524 NTCREATEX_SHARE_ACCESS_READ |
1525 NTCREATEX_SHARE_ACCESS_WRITE,
1533 determine if delete on close is set on
1535 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h,
1536 int *open_count, char **path)
1541 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1542 &del_on_close, open_count, path);
1543 if (!NT_STATUS_IS_OK(status)) {
1544 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1548 return del_on_close;