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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "vfs_posix.h"
25 #include "system/dir.h"
26 #include "system/time.h"
27 #include "dlinklist.h"
28 #include "messaging/messaging.h"
29 #include "librpc/gen_ndr/xattr.h"
32 find open file handle given fnum
34 struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
35 struct ntvfs_request *req, struct ntvfs_handle *h)
40 p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs);
43 f = talloc_get_type(p, struct pvfs_file);
46 if (req->session_info != f->session_info) {
47 DEBUG(2,("pvfs_find_fd: attempt to use wrong session for handle %p\n",h));
55 cleanup a open directory handle
57 static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
62 if (h->name->stream_name == NULL &&
63 pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
66 status = pvfs_xattr_unlink_hook(h->pvfs, path);
67 if (!NT_STATUS_IS_OK(status)) {
68 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
69 path, nt_errstr(status)));
71 if (rmdir(path) != 0) {
72 DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
73 path, strerror(errno)));
79 if (h->have_opendb_entry) {
83 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
85 DEBUG(0,("Unable to lock opendb for close\n"));
89 status = odb_close_file(lck, h);
90 if (!NT_STATUS_IS_OK(status)) {
91 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
92 h->name->full_name, nt_errstr(status)));
102 cleanup a open directory fnum
104 static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
106 DLIST_REMOVE(f->pvfs->files.list, f);
107 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
113 setup any EAs and the ACL on newly created files/directories
115 static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
116 struct ntvfs_request *req,
117 struct pvfs_filename *name,
118 int fd, struct pvfs_file *f,
123 /* setup any EAs that were asked for */
124 if (io->ntcreatex.in.ea_list) {
125 status = pvfs_setfileinfo_ea_set(pvfs, name, fd,
126 io->ntcreatex.in.ea_list->num_eas,
127 io->ntcreatex.in.ea_list->eas);
128 if (!NT_STATUS_IS_OK(status)) {
133 /* setup an initial sec_desc if requested */
134 if (io->ntcreatex.in.sec_desc) {
135 union smb_setfileinfo set;
137 * TODO: set the full ACL!
138 * - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
139 * when a SACL is present on the sd,
140 * but the user doesn't have SeSecurityPrivilege
143 set.set_secdesc.in.file.ntvfs = f->ntvfs;
144 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
145 set.set_secdesc.in.sd = io->ntcreatex.in.sec_desc;
147 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
149 /* otherwise setup an inherited acl from the parent */
150 status = pvfs_acl_inherit(pvfs, req, name, fd);
157 form the lock context used for opendb locking. Note that we must
158 zero here to take account of possible padding on some architectures
160 static NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
161 TALLOC_CTX *mem_ctx, DATA_BLOB *key)
167 ZERO_STRUCT(lock_context);
169 lock_context.device = name->st.st_dev;
170 lock_context.inode = name->st.st_ino;
172 *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
173 if (key->data == NULL) {
174 return NT_STATUS_NO_MEMORY;
184 static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
185 struct ntvfs_request *req,
186 struct pvfs_filename *name,
190 struct ntvfs_handle *h;
192 uint32_t create_action;
193 uint32_t access_mask = io->generic.in.access_mask;
194 struct odb_lock *lck;
196 uint32_t create_options;
197 uint32_t share_access;
199 create_options = io->generic.in.create_options;
200 share_access = io->generic.in.share_access;
202 if (name->stream_name) {
203 return NT_STATUS_NOT_A_DIRECTORY;
206 /* if the client says it must be a directory, and it isn't,
208 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
209 return NT_STATUS_NOT_A_DIRECTORY;
212 switch (io->generic.in.open_disposition) {
213 case NTCREATEX_DISP_OPEN_IF:
216 case NTCREATEX_DISP_OPEN:
218 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
222 case NTCREATEX_DISP_CREATE:
224 return NT_STATUS_OBJECT_NAME_COLLISION;
228 case NTCREATEX_DISP_OVERWRITE_IF:
229 case NTCREATEX_DISP_OVERWRITE:
230 case NTCREATEX_DISP_SUPERSEDE:
232 return NT_STATUS_INVALID_PARAMETER;
235 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
236 NT_STATUS_NOT_OK_RETURN(status);
238 f = talloc(h, struct pvfs_file);
240 return NT_STATUS_NO_MEMORY;
243 f->handle = talloc(f, struct pvfs_file_handle);
244 if (f->handle == NULL) {
245 return NT_STATUS_NO_MEMORY;
249 /* check the security descriptor */
250 status = pvfs_access_check(pvfs, req, name, &access_mask);
252 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
254 if (!NT_STATUS_IS_OK(status)) {
259 f->session_info = req->session_info;
260 f->smbpid = req->smbpid;
262 f->pending_list = NULL;
264 f->share_access = io->generic.in.share_access;
265 f->impersonation = io->generic.in.impersonation;
266 f->access_mask = access_mask;
267 f->brl_handle = NULL;
268 f->notify_buffer = NULL;
271 f->handle->pvfs = pvfs;
272 f->handle->name = talloc_steal(f->handle, name);
274 f->handle->odb_locking_key = data_blob(NULL, 0);
275 f->handle->create_options = io->generic.in.create_options;
276 f->handle->seek_offset = 0;
277 f->handle->position = 0;
279 f->handle->sticky_write_time = False;
281 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
282 pvfs_directory_empty(pvfs, f->handle->name)) {
285 del_on_close = False;
289 /* form the lock context used for opendb locking */
290 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
291 if (!NT_STATUS_IS_OK(status)) {
295 /* get a lock on this file before the actual open */
296 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
298 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
300 /* we were supposed to do a blocking lock, so something
302 return NT_STATUS_INTERNAL_DB_CORRUPTION;
305 /* see if we are allowed to open at the same time as existing opens */
306 status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
307 share_access, access_mask, del_on_close,
308 name->full_name, OPLOCK_NONE, NULL);
310 if (!NT_STATUS_IS_OK(status)) {
315 f->handle->have_opendb_entry = True;
318 DLIST_ADD(pvfs->files.list, f);
320 /* setup destructors to avoid leaks on abnormal termination */
321 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
322 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
325 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
326 mode_t mode = pvfs_fileperms(pvfs, attrib);
328 if (mkdir(name->full_name, mode) == -1) {
329 return pvfs_map_errno(pvfs,errno);
332 pvfs_xattr_unlink_hook(pvfs, name->full_name);
334 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
335 if (!NT_STATUS_IS_OK(status)) {
339 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
340 if (!NT_STATUS_IS_OK(status)) {
344 /* form the lock context used for opendb locking */
345 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
346 if (!NT_STATUS_IS_OK(status)) {
350 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
352 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
354 /* we were supposed to do a blocking lock, so something
356 return NT_STATUS_INTERNAL_DB_CORRUPTION;
359 status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
360 share_access, access_mask, del_on_close,
361 name->full_name, OPLOCK_NONE, NULL);
363 if (!NT_STATUS_IS_OK(status)) {
367 f->handle->have_opendb_entry = True;
369 create_action = NTCREATEX_ACTION_CREATED;
371 notify_trigger(pvfs->notify_context,
373 FILE_NOTIFY_CHANGE_DIR_NAME,
376 create_action = NTCREATEX_ACTION_EXISTED;
380 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
383 /* the open succeeded, keep this handle permanently */
384 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
385 if (!NT_STATUS_IS_OK(status)) {
389 io->generic.out.oplock_level = OPLOCK_NONE;
390 io->generic.out.file.ntvfs = h;
391 io->generic.out.create_action = create_action;
392 io->generic.out.create_time = name->dos.create_time;
393 io->generic.out.access_time = name->dos.access_time;
394 io->generic.out.write_time = name->dos.write_time;
395 io->generic.out.change_time = name->dos.change_time;
396 io->generic.out.attrib = name->dos.attrib;
397 io->generic.out.alloc_size = name->dos.alloc_size;
398 io->generic.out.size = name->st.st_size;
399 io->generic.out.file_type = FILE_TYPE_DISK;
400 io->generic.out.ipc_state = 0;
401 io->generic.out.is_directory = 1;
406 rmdir(name->full_name);
411 destroy a struct pvfs_file_handle
413 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
418 /* the write time is no longer sticky */
419 if (h->sticky_write_time) {
421 status = pvfs_dosattrib_load(h->pvfs, h->name, h->fd);
422 if (NT_STATUS_IS_OK(status)) {
423 h->name->dos.flags &= ~XATTR_ATTRIB_FLAG_STICKY_WRITE_TIME;
424 pvfs_dosattrib_save(h->pvfs, h->name, h->fd);
428 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
429 h->name->stream_name) {
431 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
432 if (!NT_STATUS_IS_OK(status)) {
433 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
434 h->name->stream_name, h->name->full_name));
439 if (close(h->fd) != 0) {
440 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
441 h->fd, h->name->full_name, strerror(errno)));
446 if (h->name->stream_name == NULL &&
447 pvfs_delete_on_close_set(h->pvfs, h, &open_count, &path) &&
450 status = pvfs_xattr_unlink_hook(h->pvfs, path);
451 if (!NT_STATUS_IS_OK(status)) {
452 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
453 path, nt_errstr(status)));
455 if (unlink(path) != 0) {
456 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
457 path, strerror(errno)));
459 notify_trigger(h->pvfs->notify_context,
460 NOTIFY_ACTION_REMOVED,
461 FILE_NOTIFY_CHANGE_FILE_NAME,
468 if (h->have_opendb_entry) {
469 struct odb_lock *lck;
472 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
474 DEBUG(0,("Unable to lock opendb for close\n"));
478 status = odb_close_file(lck, h);
479 if (!NT_STATUS_IS_OK(status)) {
480 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
481 h->name->full_name, nt_errstr(status)));
492 destroy a struct pvfs_file
494 static int pvfs_fnum_destructor(struct pvfs_file *f)
496 DLIST_REMOVE(f->pvfs->files.list, f);
497 pvfs_lock_close(f->pvfs, f);
498 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
505 form the lock context used for byte range locking. This is separate
506 from the locking key used for opendb locking as it needs to take
507 account of file streams (each stream is a separate byte range
510 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
511 struct pvfs_filename *name,
512 struct ntvfs_handle *ntvfs,
513 struct brl_handle **_h)
515 DATA_BLOB odb_key, key;
517 struct brl_handle *h;
519 status = pvfs_locking_key(name, mem_ctx, &odb_key);
520 NT_STATUS_NOT_OK_RETURN(status);
522 if (name->stream_name == NULL) {
525 key = data_blob_talloc(mem_ctx, NULL,
526 odb_key.length + strlen(name->stream_name) + 1);
527 NT_STATUS_HAVE_NO_MEMORY(key.data);
528 memcpy(key.data, odb_key.data, odb_key.length);
529 memcpy(key.data + odb_key.length,
530 name->stream_name, strlen(name->stream_name) + 1);
531 data_blob_free(&odb_key);
534 h = brl_create_handle(mem_ctx, ntvfs, &key);
535 NT_STATUS_HAVE_NO_MEMORY(h);
544 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
545 struct ntvfs_request *req,
546 struct pvfs_filename *name,
551 struct ntvfs_handle *h;
553 struct odb_lock *lck;
554 uint32_t create_options = io->generic.in.create_options;
555 uint32_t share_access = io->generic.in.share_access;
556 uint32_t access_mask = io->generic.in.access_mask;
560 struct pvfs_filename *parent;
561 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
563 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
564 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
565 return NT_STATUS_CANNOT_DELETE;
568 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
569 NT_STATUS_NOT_OK_RETURN(status);
571 /* check that the parent isn't opened with delete on close set */
572 status = pvfs_resolve_parent(pvfs, req, name, &parent);
573 if (NT_STATUS_IS_OK(status)) {
574 DATA_BLOB locking_key;
575 status = pvfs_locking_key(parent, req, &locking_key);
576 NT_STATUS_NOT_OK_RETURN(status);
577 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key,
578 &del_on_close, NULL, NULL);
579 NT_STATUS_NOT_OK_RETURN(status);
581 return NT_STATUS_DELETE_PENDING;
585 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
591 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
592 NT_STATUS_NOT_OK_RETURN(status);
594 f = talloc(h, struct pvfs_file);
595 NT_STATUS_HAVE_NO_MEMORY(f);
597 f->handle = talloc(f, struct pvfs_file_handle);
598 NT_STATUS_HAVE_NO_MEMORY(f->handle);
600 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
601 mode = pvfs_fileperms(pvfs, attrib);
603 /* create the file */
604 fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
606 return pvfs_map_errno(pvfs, errno);
609 pvfs_xattr_unlink_hook(pvfs, name->full_name);
611 /* if this was a stream create then create the stream as well */
612 if (name->stream_name) {
613 status = pvfs_stream_create(pvfs, name, fd);
614 if (!NT_STATUS_IS_OK(status)) {
620 /* re-resolve the open fd */
621 status = pvfs_resolve_name_fd(pvfs, fd, name);
622 if (!NT_STATUS_IS_OK(status)) {
627 name->dos.attrib = attrib;
628 status = pvfs_dosattrib_save(pvfs, name, fd);
629 if (!NT_STATUS_IS_OK(status)) {
634 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
635 if (!NT_STATUS_IS_OK(status)) {
639 /* form the lock context used for byte range locking and
641 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
642 if (!NT_STATUS_IS_OK(status)) {
646 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
647 if (!NT_STATUS_IS_OK(status)) {
651 /* grab a lock on the open file record */
652 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
654 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
656 /* we were supposed to do a blocking lock, so something
658 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
662 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
665 del_on_close = False;
668 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
669 oplock_level = OPLOCK_NONE;
670 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
671 oplock_level = OPLOCK_BATCH;
672 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
673 oplock_level = OPLOCK_EXCLUSIVE;
676 status = odb_open_file(lck, f->handle, name->stream_id,
677 share_access, access_mask, del_on_close,
678 name->full_name, 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 */
688 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
689 oplock_granted = OPLOCK_BATCH;
693 f->session_info = req->session_info;
694 f->smbpid = req->smbpid;
696 f->pending_list = NULL;
698 f->share_access = io->generic.in.share_access;
699 f->access_mask = access_mask;
700 f->impersonation = io->generic.in.impersonation;
701 f->notify_buffer = NULL;
704 f->handle->pvfs = pvfs;
705 f->handle->name = talloc_steal(f->handle, name);
707 f->handle->create_options = io->generic.in.create_options;
708 f->handle->seek_offset = 0;
709 f->handle->position = 0;
711 f->handle->have_opendb_entry = True;
712 f->handle->sticky_write_time = False;
714 DLIST_ADD(pvfs->files.list, f);
716 /* setup a destructor to avoid file descriptor leaks on
717 abnormal termination */
718 talloc_set_destructor(f, pvfs_fnum_destructor);
719 talloc_set_destructor(f->handle, pvfs_handle_destructor);
721 io->generic.out.oplock_level = oplock_granted;
722 io->generic.out.file.ntvfs = f->ntvfs;
723 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
724 io->generic.out.create_time = name->dos.create_time;
725 io->generic.out.access_time = name->dos.access_time;
726 io->generic.out.write_time = name->dos.write_time;
727 io->generic.out.change_time = name->dos.change_time;
728 io->generic.out.attrib = name->dos.attrib;
729 io->generic.out.alloc_size = name->dos.alloc_size;
730 io->generic.out.size = name->st.st_size;
731 io->generic.out.file_type = FILE_TYPE_DISK;
732 io->generic.out.ipc_state = 0;
733 io->generic.out.is_directory = 0;
735 /* success - keep the file handle */
736 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
737 if (!NT_STATUS_IS_OK(status)) {
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;
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->session_info == req->session_info &&
865 f2->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;
1123 f->session_info = req->session_info;
1124 f->smbpid = req->smbpid;
1126 f->pending_list = NULL;
1128 f->share_access = io->generic.in.share_access;
1129 f->access_mask = access_mask;
1130 f->impersonation = io->generic.in.impersonation;
1131 f->notify_buffer = NULL;
1134 f->handle->pvfs = pvfs;
1136 f->handle->name = talloc_steal(f->handle, name);
1137 f->handle->create_options = io->generic.in.create_options;
1138 f->handle->seek_offset = 0;
1139 f->handle->position = 0;
1140 f->handle->mode = 0;
1141 f->handle->have_opendb_entry = False;
1142 f->handle->sticky_write_time = False;
1144 /* form the lock context used for byte range locking and
1146 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1147 if (!NT_STATUS_IS_OK(status)) {
1151 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1152 if (!NT_STATUS_IS_OK(status)) {
1156 /* get a lock on this file before the actual open */
1157 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1159 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1161 /* we were supposed to do a blocking lock, so something
1163 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1166 DLIST_ADD(pvfs->files.list, f);
1168 /* setup a destructor to avoid file descriptor leaks on
1169 abnormal termination */
1170 talloc_set_destructor(f, pvfs_fnum_destructor);
1171 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1174 * Only SMB2 takes care of the delete_on_close,
1177 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1178 req->ctx->protocol == PROTOCOL_SMB2) {
1179 del_on_close = True;
1181 del_on_close = False;
1184 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1185 oplock_level = OPLOCK_NONE;
1186 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1187 oplock_level = OPLOCK_BATCH;
1188 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1189 oplock_level = OPLOCK_EXCLUSIVE;
1192 /* see if we are allowed to open at the same time as existing opens */
1193 status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
1194 share_access, access_mask, del_on_close,
1195 name->full_name, 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 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->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->session_info == req->session_info &&
1368 f->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;