2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - open and close
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "vfs_posix.h"
24 #include "system/dir.h"
25 #include "system/time.h"
26 #include "lib/util/dlinklist.h"
27 #include "messaging/messaging.h"
28 #include "librpc/gen_ndr/xattr.h"
31 find open file handle given fnum
33 struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
34 struct ntvfs_request *req, struct ntvfs_handle *h)
39 p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs);
42 f = talloc_get_type(p, struct pvfs_file);
49 cleanup a open directory handle
51 static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
53 if (h->have_opendb_entry) {
56 const char *delete_path = NULL;
58 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
60 DEBUG(0,("Unable to lock opendb for close\n"));
64 status = odb_close_file(lck, h, &delete_path);
65 if (!NT_STATUS_IS_OK(status)) {
66 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
67 h->name->full_name, nt_errstr(status)));
70 if (h->name->stream_name == NULL && delete_path) {
71 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
72 if (!NT_STATUS_IS_OK(status)) {
73 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
74 delete_path, nt_errstr(status)));
76 if (rmdir(delete_path) != 0) {
77 DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
78 delete_path, strerror(errno)));
89 cleanup a open directory fnum
91 static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
93 DLIST_REMOVE(f->pvfs->files.list, f);
94 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
100 setup any EAs and the ACL on newly created files/directories
102 static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
103 struct ntvfs_request *req,
104 struct pvfs_filename *name,
105 int fd, struct pvfs_file *f,
110 /* setup any EAs that were asked for */
111 if (io->ntcreatex.in.ea_list) {
112 status = pvfs_setfileinfo_ea_set(pvfs, name, fd,
113 io->ntcreatex.in.ea_list->num_eas,
114 io->ntcreatex.in.ea_list->eas);
115 if (!NT_STATUS_IS_OK(status)) {
120 /* setup an initial sec_desc if requested */
121 if (io->ntcreatex.in.sec_desc) {
122 union smb_setfileinfo set;
124 * TODO: set the full ACL!
125 * - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
126 * when a SACL is present on the sd,
127 * but the user doesn't have SeSecurityPrivilege
130 set.set_secdesc.in.file.ntvfs = f->ntvfs;
131 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
132 set.set_secdesc.in.sd = io->ntcreatex.in.sec_desc;
134 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
136 /* otherwise setup an inherited acl from the parent */
137 status = pvfs_acl_inherit(pvfs, req, name, fd);
144 form the lock context used for opendb locking. Note that we must
145 zero here to take account of possible padding on some architectures
147 NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
148 TALLOC_CTX *mem_ctx, DATA_BLOB *key)
154 ZERO_STRUCT(lock_context);
156 lock_context.device = name->st.st_dev;
157 lock_context.inode = name->st.st_ino;
159 *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
160 if (key->data == NULL) {
161 return NT_STATUS_NO_MEMORY;
171 static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
172 struct ntvfs_request *req,
173 struct pvfs_filename *name,
177 struct ntvfs_handle *h;
179 uint32_t create_action;
180 uint32_t access_mask = io->generic.in.access_mask;
181 struct odb_lock *lck;
183 uint32_t create_options;
184 uint32_t share_access;
187 create_options = io->generic.in.create_options;
188 share_access = io->generic.in.share_access;
190 forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false;
192 if (name->stream_name) {
194 return NT_STATUS_NOT_A_DIRECTORY;
196 return NT_STATUS_FILE_IS_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 /* found with gentest */
207 if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
208 (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
209 (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
210 return NT_STATUS_INVALID_PARAMETER;
213 switch (io->generic.in.open_disposition) {
214 case NTCREATEX_DISP_OPEN_IF:
217 case NTCREATEX_DISP_OPEN:
219 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
223 case NTCREATEX_DISP_CREATE:
225 return NT_STATUS_OBJECT_NAME_COLLISION;
229 case NTCREATEX_DISP_OVERWRITE_IF:
230 case NTCREATEX_DISP_OVERWRITE:
231 case NTCREATEX_DISP_SUPERSEDE:
233 return NT_STATUS_INVALID_PARAMETER;
236 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
237 NT_STATUS_NOT_OK_RETURN(status);
239 f = talloc(h, struct pvfs_file);
241 return NT_STATUS_NO_MEMORY;
244 f->handle = talloc(f, struct pvfs_file_handle);
245 if (f->handle == NULL) {
246 return NT_STATUS_NO_MEMORY;
250 /* check the security descriptor */
251 status = pvfs_access_check(pvfs, req, name, &access_mask);
253 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
255 NT_STATUS_NOT_OK_RETURN(status);
257 if (io->generic.in.query_maximal_access) {
258 status = pvfs_access_maximal_allowed(pvfs, req, name,
259 &io->generic.out.maximal_access);
260 NT_STATUS_NOT_OK_RETURN(status);
265 f->pending_list = NULL;
267 f->share_access = io->generic.in.share_access;
268 f->impersonation = io->generic.in.impersonation;
269 f->access_mask = access_mask;
270 f->brl_handle = NULL;
271 f->notify_buffer = NULL;
274 f->handle->pvfs = pvfs;
275 f->handle->name = talloc_steal(f->handle, name);
277 f->handle->odb_locking_key = data_blob(NULL, 0);
278 f->handle->create_options = io->generic.in.create_options;
279 f->handle->seek_offset = 0;
280 f->handle->position = 0;
282 f->handle->oplock = NULL;
283 f->handle->open_completed = false;
285 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
286 pvfs_directory_empty(pvfs, f->handle->name)) {
289 del_on_close = false;
293 /* form the lock context used for opendb locking */
294 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
295 if (!NT_STATUS_IS_OK(status)) {
299 /* get a lock on this file before the actual open */
300 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
302 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
304 /* we were supposed to do a blocking lock, so something
306 return NT_STATUS_INTERNAL_DB_CORRUPTION;
309 /* see if we are allowed to open at the same time as existing opens */
310 status = odb_can_open(lck, name->stream_id,
311 share_access, access_mask, del_on_close,
312 io->generic.in.open_disposition, false);
313 if (!NT_STATUS_IS_OK(status)) {
318 /* now really mark the file as open */
319 status = odb_open_file(lck, f->handle, name->full_name,
320 NULL, false, OPLOCK_NONE, NULL);
322 if (!NT_STATUS_IS_OK(status)) {
327 f->handle->have_opendb_entry = true;
330 DLIST_ADD(pvfs->files.list, f);
332 /* setup destructors to avoid leaks on abnormal termination */
333 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
334 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
337 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
338 mode_t mode = pvfs_fileperms(pvfs, attrib);
340 if (mkdir(name->full_name, mode) == -1) {
341 return pvfs_map_errno(pvfs,errno);
344 pvfs_xattr_unlink_hook(pvfs, name->full_name);
346 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
347 if (!NT_STATUS_IS_OK(status)) {
351 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
352 if (!NT_STATUS_IS_OK(status)) {
356 /* form the lock context used for opendb locking */
357 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
358 if (!NT_STATUS_IS_OK(status)) {
362 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
364 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
366 /* we were supposed to do a blocking lock, so something
368 return NT_STATUS_INTERNAL_DB_CORRUPTION;
371 status = odb_can_open(lck, name->stream_id,
372 share_access, access_mask, del_on_close,
373 io->generic.in.open_disposition, false);
375 if (!NT_STATUS_IS_OK(status)) {
379 status = odb_open_file(lck, f->handle, name->full_name,
380 NULL, false, OPLOCK_NONE, NULL);
382 if (!NT_STATUS_IS_OK(status)) {
386 f->handle->have_opendb_entry = true;
388 create_action = NTCREATEX_ACTION_CREATED;
390 notify_trigger(pvfs->notify_context,
392 FILE_NOTIFY_CHANGE_DIR_NAME,
395 create_action = NTCREATEX_ACTION_EXISTED;
399 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
402 /* the open succeeded, keep this handle permanently */
403 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
404 if (!NT_STATUS_IS_OK(status)) {
408 f->handle->open_completed = true;
410 io->generic.out.oplock_level = OPLOCK_NONE;
411 io->generic.out.file.ntvfs = h;
412 io->generic.out.create_action = create_action;
413 io->generic.out.create_time = name->dos.create_time;
414 io->generic.out.access_time = name->dos.access_time;
415 io->generic.out.write_time = name->dos.write_time;
416 io->generic.out.change_time = name->dos.change_time;
417 io->generic.out.attrib = name->dos.attrib;
418 io->generic.out.alloc_size = name->dos.alloc_size;
419 io->generic.out.size = name->st.st_size;
420 io->generic.out.file_type = FILE_TYPE_DISK;
421 io->generic.out.ipc_state = 0;
422 io->generic.out.is_directory = 1;
427 rmdir(name->full_name);
432 destroy a struct pvfs_file_handle
434 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
436 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
437 h->name->stream_name) {
439 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
440 if (!NT_STATUS_IS_OK(status)) {
441 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
442 h->name->stream_name, h->name->full_name));
447 if (close(h->fd) != 0) {
448 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
449 h->fd, h->name->full_name, strerror(errno)));
454 if (h->have_opendb_entry) {
455 struct odb_lock *lck;
457 const char *delete_path = NULL;
459 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
461 DEBUG(0,("Unable to lock opendb for close\n"));
465 status = odb_close_file(lck, h, &delete_path);
466 if (!NT_STATUS_IS_OK(status)) {
467 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
468 h->name->full_name, nt_errstr(status)));
471 if (h->name->stream_name == NULL &&
472 h->open_completed && delete_path) {
473 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
474 if (!NT_STATUS_IS_OK(status)) {
475 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
476 delete_path, nt_errstr(status)));
478 if (unlink(delete_path) != 0) {
479 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
480 delete_path, strerror(errno)));
482 notify_trigger(h->pvfs->notify_context,
483 NOTIFY_ACTION_REMOVED,
484 FILE_NOTIFY_CHANGE_FILE_NAME,
497 destroy a struct pvfs_file
499 static int pvfs_fnum_destructor(struct pvfs_file *f)
501 DLIST_REMOVE(f->pvfs->files.list, f);
502 pvfs_lock_close(f->pvfs, f);
503 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
510 form the lock context used for byte range locking. This is separate
511 from the locking key used for opendb locking as it needs to take
512 account of file streams (each stream is a separate byte range
515 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
516 struct pvfs_filename *name,
517 struct ntvfs_handle *ntvfs,
518 struct brl_handle **_h)
520 DATA_BLOB odb_key, key;
522 struct brl_handle *h;
524 status = pvfs_locking_key(name, mem_ctx, &odb_key);
525 NT_STATUS_NOT_OK_RETURN(status);
527 if (name->stream_name == NULL) {
530 key = data_blob_talloc(mem_ctx, NULL,
531 odb_key.length + strlen(name->stream_name) + 1);
532 NT_STATUS_HAVE_NO_MEMORY(key.data);
533 memcpy(key.data, odb_key.data, odb_key.length);
534 memcpy(key.data + odb_key.length,
535 name->stream_name, strlen(name->stream_name) + 1);
536 data_blob_free(&odb_key);
539 h = brl_create_handle(mem_ctx, ntvfs, &key);
540 NT_STATUS_HAVE_NO_MEMORY(h);
549 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
550 struct ntvfs_request *req,
551 struct pvfs_filename *name,
556 struct ntvfs_handle *h;
558 struct odb_lock *lck;
559 uint32_t create_options = io->generic.in.create_options;
560 uint32_t share_access = io->generic.in.share_access;
561 uint32_t access_mask = io->generic.in.access_mask;
565 struct pvfs_filename *parent;
566 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
567 bool allow_level_II_oplock = false;
569 if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
570 return NT_STATUS_INVALID_PARAMETER;
573 if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
574 return NT_STATUS_ACCESS_DENIED;
577 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
578 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
579 return NT_STATUS_CANNOT_DELETE;
582 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
583 NT_STATUS_NOT_OK_RETURN(status);
585 if (io->generic.in.query_maximal_access) {
586 status = pvfs_access_maximal_allowed(pvfs, req, name,
587 &io->generic.out.maximal_access);
588 NT_STATUS_NOT_OK_RETURN(status);
591 /* check that the parent isn't opened with delete on close set */
592 status = pvfs_resolve_parent(pvfs, req, name, &parent);
593 if (NT_STATUS_IS_OK(status)) {
594 DATA_BLOB locking_key;
595 status = pvfs_locking_key(parent, req, &locking_key);
596 NT_STATUS_NOT_OK_RETURN(status);
597 status = odb_get_delete_on_close(pvfs->odb_context, &locking_key,
599 NT_STATUS_NOT_OK_RETURN(status);
601 return NT_STATUS_DELETE_PENDING;
605 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
611 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
612 NT_STATUS_NOT_OK_RETURN(status);
614 f = talloc(h, struct pvfs_file);
615 NT_STATUS_HAVE_NO_MEMORY(f);
617 f->handle = talloc(f, struct pvfs_file_handle);
618 NT_STATUS_HAVE_NO_MEMORY(f->handle);
620 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
621 mode = pvfs_fileperms(pvfs, attrib);
623 /* create the file */
624 fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
626 return pvfs_map_errno(pvfs, errno);
629 pvfs_xattr_unlink_hook(pvfs, name->full_name);
631 /* if this was a stream create then create the stream as well */
632 if (name->stream_name) {
633 status = pvfs_stream_create(pvfs, name, fd);
634 if (!NT_STATUS_IS_OK(status)) {
640 /* re-resolve the open fd */
641 status = pvfs_resolve_name_fd(pvfs, fd, name);
642 if (!NT_STATUS_IS_OK(status)) {
647 /* support initial alloc sizes */
648 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
649 name->dos.attrib = attrib;
650 status = pvfs_dosattrib_save(pvfs, name, fd);
651 if (!NT_STATUS_IS_OK(status)) {
656 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
657 if (!NT_STATUS_IS_OK(status)) {
661 /* form the lock context used for byte range locking and
663 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
664 if (!NT_STATUS_IS_OK(status)) {
668 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
669 if (!NT_STATUS_IS_OK(status)) {
673 /* grab a lock on the open file record */
674 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
676 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
678 /* we were supposed to do a blocking lock, so something
680 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
684 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
687 del_on_close = false;
690 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
691 oplock_level = OPLOCK_NONE;
692 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
693 oplock_level = OPLOCK_BATCH;
694 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
695 oplock_level = OPLOCK_EXCLUSIVE;
698 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
699 allow_level_II_oplock = true;
702 status = odb_can_open(lck, name->stream_id,
703 share_access, access_mask, del_on_close,
704 io->generic.in.open_disposition, false);
705 if (!NT_STATUS_IS_OK(status)) {
707 /* bad news, we must have hit a race - we don't delete the file
708 here as the most likely scenario is that someone else created
709 the file at the same time */
716 f->pending_list = NULL;
718 f->share_access = io->generic.in.share_access;
719 f->access_mask = access_mask;
720 f->impersonation = io->generic.in.impersonation;
721 f->notify_buffer = NULL;
724 f->handle->pvfs = pvfs;
725 f->handle->name = talloc_steal(f->handle, name);
727 f->handle->create_options = io->generic.in.create_options;
728 f->handle->seek_offset = 0;
729 f->handle->position = 0;
731 f->handle->oplock = NULL;
732 f->handle->have_opendb_entry = true;
733 f->handle->open_completed = false;
735 status = odb_open_file(lck, f->handle, name->full_name,
736 &f->handle->fd, allow_level_II_oplock,
737 oplock_level, &oplock_granted);
739 if (!NT_STATUS_IS_OK(status)) {
740 /* bad news, we must have hit a race - we don't delete the file
741 here as the most likely scenario is that someone else created
742 the file at the same time */
747 DLIST_ADD(pvfs->files.list, f);
749 /* setup a destructor to avoid file descriptor leaks on
750 abnormal termination */
751 talloc_set_destructor(f, pvfs_fnum_destructor);
752 talloc_set_destructor(f->handle, pvfs_handle_destructor);
754 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
755 oplock_granted = OPLOCK_BATCH;
756 } else if (oplock_granted != OPLOCK_NONE) {
757 status = pvfs_setup_oplock(f, oplock_granted);
758 if (!NT_STATUS_IS_OK(status)) {
763 io->generic.out.oplock_level = oplock_granted;
764 io->generic.out.file.ntvfs = f->ntvfs;
765 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
766 io->generic.out.create_time = name->dos.create_time;
767 io->generic.out.access_time = name->dos.access_time;
768 io->generic.out.write_time = name->dos.write_time;
769 io->generic.out.change_time = name->dos.change_time;
770 io->generic.out.attrib = name->dos.attrib;
771 io->generic.out.alloc_size = name->dos.alloc_size;
772 io->generic.out.size = name->st.st_size;
773 io->generic.out.file_type = FILE_TYPE_DISK;
774 io->generic.out.ipc_state = 0;
775 io->generic.out.is_directory = 0;
777 /* success - keep the file handle */
778 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
779 if (!NT_STATUS_IS_OK(status)) {
783 f->handle->open_completed = true;
785 notify_trigger(pvfs->notify_context,
787 FILE_NOTIFY_CHANGE_FILE_NAME,
794 unlink(name->full_name);
799 state of a pending retry
801 struct pvfs_odb_retry {
802 struct ntvfs_module_context *ntvfs;
803 struct ntvfs_request *req;
804 DATA_BLOB odb_locking_key;
807 void (*callback)(struct pvfs_odb_retry *r,
808 struct ntvfs_module_context *ntvfs,
809 struct ntvfs_request *req,
812 enum pvfs_wait_notice reason);
815 /* destroy a pending request */
816 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
818 struct pvfs_state *pvfs = r->ntvfs->private_data;
819 if (r->odb_locking_key.data) {
820 struct odb_lock *lck;
821 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
823 odb_remove_pending(lck, r);
830 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
832 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
834 if (reason == PVFS_WAIT_EVENT) {
836 * The pending odb entry is already removed.
837 * We use a null locking key to indicate this
840 data_blob_free(&r->odb_locking_key);
843 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
847 setup for a retry of a request that was rejected
850 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
851 struct ntvfs_request *req,
852 struct odb_lock *lck,
853 struct timeval end_time,
856 void (*callback)(struct pvfs_odb_retry *r,
857 struct ntvfs_module_context *ntvfs,
858 struct ntvfs_request *req,
861 enum pvfs_wait_notice reason))
863 struct pvfs_state *pvfs = ntvfs->private_data;
864 struct pvfs_odb_retry *r;
865 struct pvfs_wait *wait_handle;
868 r = talloc(req, struct pvfs_odb_retry);
869 NT_STATUS_HAVE_NO_MEMORY(r);
874 r->private_data = private_data;
875 r->callback = callback;
876 r->odb_locking_key = odb_get_key(r, lck);
877 if (r->odb_locking_key.data == NULL) {
878 return NT_STATUS_NO_MEMORY;
881 /* setup a pending lock */
882 status = odb_open_file_pending(lck, r);
883 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
885 * maybe only a unix application
888 data_blob_free(&r->odb_locking_key);
889 } else if (!NT_STATUS_IS_OK(status)) {
895 talloc_set_destructor(r, pvfs_odb_retry_destructor);
897 wait_handle = pvfs_wait_message(pvfs, req,
898 MSG_PVFS_RETRY_OPEN, end_time,
899 pvfs_odb_retry_callback, r);
900 if (wait_handle == NULL) {
901 return NT_STATUS_NO_MEMORY;
904 talloc_steal(r, wait_handle);
910 retry an open after a sharing violation
912 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
913 struct ntvfs_module_context *ntvfs,
914 struct ntvfs_request *req,
917 enum pvfs_wait_notice reason)
919 union smb_open *io = talloc_get_type(_io, union smb_open);
920 struct timeval *final_timeout = NULL;
924 final_timeout = talloc_get_type(private_data,
928 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
929 just a bug in their server, but we better do the same */
930 if (reason == PVFS_WAIT_CANCEL) {
934 if (reason == PVFS_WAIT_TIMEOUT) {
936 !timeval_expired(final_timeout)) {
938 * we need to retry periodictly
939 * after an EAGAIN as there's
940 * no way the kernel tell us
941 * an oplock is released.
945 /* if it timed out, then give the failure
948 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
949 req->async_states->send_fn(req);
956 /* try the open again, which could trigger another retry setup
957 if it wants to, so we have to unmark the async flag so we
958 will know if it does a second async reply */
959 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
961 status = pvfs_open(ntvfs, req, io);
962 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
963 /* the 2nd try also replied async, so we don't send
968 /* re-mark it async, just in case someone up the chain does
970 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
972 /* send the reply up the chain */
973 req->async_states->status = status;
974 req->async_states->send_fn(req);
979 special handling for openx DENY_DOS semantics
981 This function attempts a reference open using an existing handle. If its allowed,
982 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
983 open processing continues.
985 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
986 struct ntvfs_request *req, union smb_open *io,
987 struct pvfs_file *f, struct odb_lock *lck)
989 struct pvfs_state *pvfs = ntvfs->private_data;
990 struct pvfs_file *f2;
991 struct pvfs_filename *name;
994 /* search for an existing open with the right parameters. Note
995 the magic ntcreatex options flag, which is set in the
996 generic mapping code. This might look ugly, but its
997 actually pretty much now w2k does it internally as well.
999 If you look at the BASE-DENYDOS test you will see that a
1000 DENY_DOS is a very special case, and in the right
1001 circumstances you actually get the _same_ handle back
1002 twice, rather than a new handle.
1004 for (f2=pvfs->files.list;f2;f2=f2->next) {
1006 f2->ntvfs->session_info == req->session_info &&
1007 f2->ntvfs->smbpid == req->smbpid &&
1008 (f2->handle->create_options &
1009 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
1010 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
1011 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1012 strcasecmp_m(f2->handle->name->original_name,
1013 io->generic.in.fname)==0) {
1019 return NT_STATUS_SHARING_VIOLATION;
1022 /* quite an insane set of semantics ... */
1023 if (is_exe_filename(io->generic.in.fname) &&
1024 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1025 return NT_STATUS_SHARING_VIOLATION;
1029 setup a reference to the existing handle
1031 talloc_free(f->handle);
1032 f->handle = talloc_reference(f, f2->handle);
1036 name = f->handle->name;
1038 io->generic.out.oplock_level = OPLOCK_NONE;
1039 io->generic.out.file.ntvfs = f->ntvfs;
1040 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1041 io->generic.out.create_time = name->dos.create_time;
1042 io->generic.out.access_time = name->dos.access_time;
1043 io->generic.out.write_time = name->dos.write_time;
1044 io->generic.out.change_time = name->dos.change_time;
1045 io->generic.out.attrib = name->dos.attrib;
1046 io->generic.out.alloc_size = name->dos.alloc_size;
1047 io->generic.out.size = name->st.st_size;
1048 io->generic.out.file_type = FILE_TYPE_DISK;
1049 io->generic.out.ipc_state = 0;
1050 io->generic.out.is_directory = 0;
1052 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1053 NT_STATUS_NOT_OK_RETURN(status);
1055 return NT_STATUS_OK;
1061 setup for a open retry after a sharing violation
1063 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1064 struct ntvfs_request *req,
1066 struct pvfs_file *f,
1067 struct odb_lock *lck,
1068 NTSTATUS parent_status)
1070 struct pvfs_state *pvfs = ntvfs->private_data;
1072 struct timeval end_time;
1073 struct timeval *final_timeout = NULL;
1075 if (io->generic.in.create_options &
1076 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1077 /* see if we can satisfy the request using the special DENY_DOS
1079 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1080 if (NT_STATUS_IS_OK(status)) {
1085 /* the retry should allocate a new file handle */
1088 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1089 end_time = timeval_add(&req->statistics.request_time,
1090 0, pvfs->sharing_violation_delay);
1091 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1092 end_time = timeval_add(&req->statistics.request_time,
1093 pvfs->oplock_break_timeout, 0);
1094 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1096 * we got EAGAIN which means a unix application
1097 * has an oplock or share mode
1099 * we retry every 4/5 of the sharing violation delay
1100 * to see if the unix application
1101 * has released the oplock or share mode.
1103 final_timeout = talloc(req, struct timeval);
1104 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1105 *final_timeout = timeval_add(&req->statistics.request_time,
1106 pvfs->oplock_break_timeout,
1108 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1109 end_time = timeval_min(final_timeout, &end_time);
1111 return NT_STATUS_INTERNAL_ERROR;
1114 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1115 final_timeout, pvfs_retry_open_sharing);
1121 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1122 struct ntvfs_request *req, union smb_open *io)
1124 struct pvfs_state *pvfs = ntvfs->private_data;
1126 struct pvfs_filename *name;
1127 struct pvfs_file *f;
1128 struct ntvfs_handle *h;
1131 struct odb_lock *lck;
1132 uint32_t create_options;
1133 uint32_t share_access;
1134 uint32_t access_mask;
1135 uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1137 bool stream_existed, stream_truncate=false;
1138 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1139 bool allow_level_II_oplock = false;
1141 /* use the generic mapping code to avoid implementing all the
1142 different open calls. */
1143 if (io->generic.level != RAW_OPEN_GENERIC &&
1144 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1145 return ntvfs_map_open(ntvfs, req, io);
1148 ZERO_STRUCT(io->generic.out);
1150 create_options = io->generic.in.create_options;
1151 share_access = io->generic.in.share_access;
1152 access_mask = io->generic.in.access_mask;
1154 if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1155 return NT_STATUS_INVALID_PARAMETER;
1158 /* some create options are not supported */
1159 if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1160 return NT_STATUS_NOT_SUPPORTED;
1163 /* other create options are not allowed */
1164 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1165 !(access_mask & SEC_STD_DELETE)) {
1166 return NT_STATUS_INVALID_PARAMETER;
1169 if (access_mask & SEC_MASK_INVALID) {
1170 return NT_STATUS_ACCESS_DENIED;
1173 /* what does this bit really mean?? */
1174 if (req->ctx->protocol == PROTOCOL_SMB2 &&
1175 access_mask == SEC_STD_SYNCHRONIZE) {
1176 return NT_STATUS_ACCESS_DENIED;
1179 if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1180 FILE_ATTRIBUTE_VOLUME|
1181 (~FILE_ATTRIBUTE_ALL_MASK))) {
1182 return NT_STATUS_INVALID_PARAMETER;
1185 /* we ignore some file_attr bits */
1186 io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED |
1187 FILE_ATTRIBUTE_COMPRESSED |
1188 FILE_ATTRIBUTE_REPARSE_POINT |
1189 FILE_ATTRIBUTE_SPARSE |
1190 FILE_ATTRIBUTE_NORMAL);
1192 /* resolve the cifs name to a posix name */
1193 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1194 PVFS_RESOLVE_STREAMS, &name);
1195 if (!NT_STATUS_IS_OK(status)) {
1199 /* if the client specified that it must not be a directory then
1200 check that it isn't */
1201 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1202 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1203 return NT_STATUS_FILE_IS_A_DIRECTORY;
1206 /* if the client specified that it must be a directory then
1208 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1209 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1210 return NT_STATUS_NOT_A_DIRECTORY;
1213 /* directory opens are handled separately */
1214 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1215 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1216 return pvfs_open_directory(pvfs, req, name, io);
1219 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1220 open doesn't match */
1221 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1225 switch (io->generic.in.open_disposition) {
1226 case NTCREATEX_DISP_SUPERSEDE:
1227 case NTCREATEX_DISP_OVERWRITE_IF:
1228 if (name->stream_name == NULL) {
1231 stream_truncate = true;
1233 create_action = NTCREATEX_ACTION_TRUNCATED;
1236 case NTCREATEX_DISP_OPEN:
1237 if (!name->stream_exists) {
1238 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1243 case NTCREATEX_DISP_OVERWRITE:
1244 if (!name->stream_exists) {
1245 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1247 if (name->stream_name == NULL) {
1250 stream_truncate = true;
1252 create_action = NTCREATEX_ACTION_TRUNCATED;
1255 case NTCREATEX_DISP_CREATE:
1256 if (name->stream_exists) {
1257 return NT_STATUS_OBJECT_NAME_COLLISION;
1262 case NTCREATEX_DISP_OPEN_IF:
1267 return NT_STATUS_INVALID_PARAMETER;
1270 /* handle creating a new file separately */
1271 if (!name->exists) {
1272 status = pvfs_create_file(pvfs, req, name, io);
1273 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1277 /* we've hit a race - the file was created during this call */
1278 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1282 /* try re-resolving the name */
1283 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1284 if (!NT_STATUS_IS_OK(status)) {
1287 /* fall through to a normal open */
1290 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1291 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1292 return NT_STATUS_CANNOT_DELETE;
1295 /* check the security descriptor */
1296 status = pvfs_access_check(pvfs, req, name, &access_mask);
1297 NT_STATUS_NOT_OK_RETURN(status);
1299 if (io->generic.in.query_maximal_access) {
1300 status = pvfs_access_maximal_allowed(pvfs, req, name,
1301 &io->generic.out.maximal_access);
1302 NT_STATUS_NOT_OK_RETURN(status);
1305 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1306 NT_STATUS_NOT_OK_RETURN(status);
1308 f = talloc(h, struct pvfs_file);
1310 return NT_STATUS_NO_MEMORY;
1313 f->handle = talloc(f, struct pvfs_file_handle);
1314 if (f->handle == NULL) {
1315 return NT_STATUS_NO_MEMORY;
1320 f->pending_list = NULL;
1322 f->share_access = io->generic.in.share_access;
1323 f->access_mask = access_mask;
1324 f->impersonation = io->generic.in.impersonation;
1325 f->notify_buffer = NULL;
1328 f->handle->pvfs = pvfs;
1330 f->handle->name = talloc_steal(f->handle, name);
1331 f->handle->create_options = io->generic.in.create_options;
1332 f->handle->seek_offset = 0;
1333 f->handle->position = 0;
1334 f->handle->mode = 0;
1335 f->handle->oplock = NULL;
1336 f->handle->have_opendb_entry = false;
1337 f->handle->open_completed = false;
1339 /* form the lock context used for byte range locking and
1341 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1342 if (!NT_STATUS_IS_OK(status)) {
1346 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1347 if (!NT_STATUS_IS_OK(status)) {
1351 /* get a lock on this file before the actual open */
1352 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1354 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1356 /* we were supposed to do a blocking lock, so something
1358 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1361 DLIST_ADD(pvfs->files.list, f);
1363 /* setup a destructor to avoid file descriptor leaks on
1364 abnormal termination */
1365 talloc_set_destructor(f, pvfs_fnum_destructor);
1366 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1369 * Only SMB2 takes care of the delete_on_close,
1372 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1373 req->ctx->protocol == PROTOCOL_SMB2) {
1374 del_on_close = true;
1376 del_on_close = false;
1379 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1380 oplock_level = OPLOCK_NONE;
1381 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1382 oplock_level = OPLOCK_BATCH;
1383 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1384 oplock_level = OPLOCK_EXCLUSIVE;
1387 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1388 allow_level_II_oplock = true;
1391 /* see if we are allowed to open at the same time as existing opens */
1392 status = odb_can_open(lck, name->stream_id,
1393 share_access, access_mask, del_on_close,
1394 io->generic.in.open_disposition, false);
1397 * on a sharing violation we need to retry when the file is closed by
1398 * the other user, or after 1 second
1399 * on a non granted oplock we need to retry when the file is closed by
1400 * the other user, or after 30 seconds
1402 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1403 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1404 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1405 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1408 if (!NT_STATUS_IS_OK(status)) {
1413 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1419 /* do the actual open */
1420 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1422 status = pvfs_map_errno(f->pvfs, errno);
1425 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1427 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1428 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1429 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1438 /* now really mark the file as open */
1439 status = odb_open_file(lck, f->handle, name->full_name,
1440 &f->handle->fd, allow_level_II_oplock,
1441 oplock_level, &oplock_granted);
1443 if (!NT_STATUS_IS_OK(status)) {
1448 f->handle->have_opendb_entry = true;
1450 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1451 oplock_granted = OPLOCK_BATCH;
1452 } else if (oplock_granted != OPLOCK_NONE) {
1453 status = pvfs_setup_oplock(f, oplock_granted);
1454 if (!NT_STATUS_IS_OK(status)) {
1460 stream_existed = name->stream_exists;
1462 /* if this was a stream create then create the stream as well */
1463 if (!name->stream_exists) {
1464 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1465 if (!NT_STATUS_IS_OK(status)) {
1469 if (stream_truncate) {
1470 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1471 if (!NT_STATUS_IS_OK(status)) {
1478 /* re-resolve the open fd */
1479 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
1480 if (!NT_STATUS_IS_OK(status)) {
1485 if (f->handle->name->stream_id == 0 &&
1486 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1487 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1488 /* for overwrite we need to replace file permissions */
1489 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1490 mode_t mode = pvfs_fileperms(pvfs, attrib);
1491 if (fchmod(fd, mode) == -1) {
1493 return pvfs_map_errno(pvfs, errno);
1495 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1496 name->dos.attrib = attrib;
1497 status = pvfs_dosattrib_save(pvfs, name, fd);
1498 if (!NT_STATUS_IS_OK(status)) {
1506 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1507 NT_STATUS_NOT_OK_RETURN(status);
1509 /* mark the open as having completed fully, so delete on close
1511 f->handle->open_completed = true;
1513 io->generic.out.oplock_level = oplock_granted;
1514 io->generic.out.file.ntvfs = h;
1515 io->generic.out.create_action = stream_existed?
1516 create_action:NTCREATEX_ACTION_CREATED;
1518 io->generic.out.create_time = name->dos.create_time;
1519 io->generic.out.access_time = name->dos.access_time;
1520 io->generic.out.write_time = name->dos.write_time;
1521 io->generic.out.change_time = name->dos.change_time;
1522 io->generic.out.attrib = name->dos.attrib;
1523 io->generic.out.alloc_size = name->dos.alloc_size;
1524 io->generic.out.size = name->st.st_size;
1525 io->generic.out.file_type = FILE_TYPE_DISK;
1526 io->generic.out.ipc_state = 0;
1527 io->generic.out.is_directory = 0;
1529 return NT_STATUS_OK;
1536 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1537 struct ntvfs_request *req, union smb_close *io)
1539 struct pvfs_state *pvfs = ntvfs->private_data;
1540 struct pvfs_file *f;
1541 struct utimbuf unix_times;
1543 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1544 return NT_STATUS_DOS(ERRSRV, ERRerror);
1547 if (io->generic.level != RAW_CLOSE_GENERIC) {
1548 return ntvfs_map_close(ntvfs, req, io);
1551 f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1553 return NT_STATUS_INVALID_HANDLE;
1556 if (!null_time(io->generic.in.write_time)) {
1557 unix_times.actime = 0;
1558 unix_times.modtime = io->close.in.write_time;
1559 utime(f->handle->name->full_name, &unix_times);
1562 if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1563 struct pvfs_filename *name;
1565 struct pvfs_file_handle *h = f->handle;
1567 status = pvfs_resolve_name_handle(pvfs, h);
1568 if (!NT_STATUS_IS_OK(status)) {
1573 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1574 io->generic.out.create_time = name->dos.create_time;
1575 io->generic.out.access_time = name->dos.access_time;
1576 io->generic.out.write_time = name->dos.write_time;
1577 io->generic.out.change_time = name->dos.change_time;
1578 io->generic.out.alloc_size = name->dos.alloc_size;
1579 io->generic.out.size = name->st.st_size;
1580 io->generic.out.file_attr = name->dos.attrib;
1582 ZERO_STRUCT(io->generic.out);
1587 return NT_STATUS_OK;
1592 logoff - close all file descriptors open by a vuid
1594 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1595 struct ntvfs_request *req)
1597 struct pvfs_state *pvfs = ntvfs->private_data;
1598 struct pvfs_file *f, *next;
1600 for (f=pvfs->files.list;f;f=next) {
1602 if (f->ntvfs->session_info == req->session_info) {
1607 return NT_STATUS_OK;
1612 exit - close files for the current pid
1614 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1615 struct ntvfs_request *req)
1617 struct pvfs_state *pvfs = ntvfs->private_data;
1618 struct pvfs_file *f, *next;
1620 for (f=pvfs->files.list;f;f=next) {
1622 if (f->ntvfs->session_info == req->session_info &&
1623 f->ntvfs->smbpid == req->smbpid) {
1628 return NT_STATUS_OK;
1633 change the delete on close flag on an already open file
1635 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1636 struct ntvfs_request *req,
1637 struct pvfs_file *f, bool del_on_close)
1639 struct odb_lock *lck;
1642 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1643 return NT_STATUS_CANNOT_DELETE;
1646 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1647 !pvfs_directory_empty(pvfs, f->handle->name)) {
1648 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1652 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1654 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1657 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1659 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1662 status = odb_set_delete_on_close(lck, del_on_close);
1671 determine if a file can be deleted, or if it is prevented by an
1674 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1675 struct ntvfs_request *req,
1676 struct pvfs_filename *name,
1677 struct odb_lock **lckp)
1681 struct odb_lock *lck;
1682 uint32_t share_access;
1683 uint32_t access_mask;
1684 bool delete_on_close;
1686 status = pvfs_locking_key(name, name, &key);
1687 if (!NT_STATUS_IS_OK(status)) {
1688 return NT_STATUS_NO_MEMORY;
1691 lck = odb_lock(req, pvfs->odb_context, &key);
1693 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1694 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1697 share_access = NTCREATEX_SHARE_ACCESS_READ |
1698 NTCREATEX_SHARE_ACCESS_WRITE |
1699 NTCREATEX_SHARE_ACCESS_DELETE;
1700 access_mask = SEC_STD_DELETE;
1701 delete_on_close = true;
1703 status = odb_can_open(lck, name->stream_id,
1704 share_access, access_mask, delete_on_close,
1705 NTCREATEX_DISP_OPEN, false);
1707 if (NT_STATUS_IS_OK(status)) {
1708 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1712 * if it's a sharing violation or we got no oplock
1713 * only keep the lock if the caller requested access
1716 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1717 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1723 } else if (!NT_STATUS_IS_OK(status)) {
1736 determine if a file can be renamed, or if it is prevented by an
1739 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1740 struct ntvfs_request *req,
1741 struct pvfs_filename *name,
1742 struct odb_lock **lckp)
1746 struct odb_lock *lck;
1747 uint32_t share_access;
1748 uint32_t access_mask;
1749 bool delete_on_close;
1751 status = pvfs_locking_key(name, name, &key);
1752 if (!NT_STATUS_IS_OK(status)) {
1753 return NT_STATUS_NO_MEMORY;
1756 lck = odb_lock(req, pvfs->odb_context, &key);
1758 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1759 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1762 share_access = NTCREATEX_SHARE_ACCESS_READ |
1763 NTCREATEX_SHARE_ACCESS_WRITE;
1764 access_mask = SEC_STD_DELETE;
1765 delete_on_close = false;
1767 status = odb_can_open(lck, name->stream_id,
1768 share_access, access_mask, delete_on_close,
1769 NTCREATEX_DISP_OPEN, false);
1772 * if it's a sharing violation or we got no oplock
1773 * only keep the lock if the caller requested access
1776 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1777 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1783 } else if (!NT_STATUS_IS_OK(status)) {
1796 determine if the file size of a file can be changed,
1797 or if it is prevented by an already open file
1799 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1800 struct ntvfs_request *req,
1801 struct pvfs_filename *name,
1802 struct odb_lock **lckp)
1806 struct odb_lock *lck;
1807 uint32_t share_access;
1808 uint32_t access_mask;
1810 bool delete_on_close;
1812 status = pvfs_locking_key(name, name, &key);
1813 if (!NT_STATUS_IS_OK(status)) {
1814 return NT_STATUS_NO_MEMORY;
1817 lck = odb_lock(req, pvfs->odb_context, &key);
1819 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1820 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1823 share_access = NTCREATEX_SHARE_ACCESS_READ |
1824 NTCREATEX_SHARE_ACCESS_WRITE |
1825 NTCREATEX_SHARE_ACCESS_DELETE;
1827 * I would have thought that we would need to pass
1828 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1830 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1831 * to set the filesize.
1835 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1836 delete_on_close = false;
1837 break_to_none = true;
1839 status = odb_can_open(lck, name->stream_id,
1840 share_access, access_mask, delete_on_close,
1841 NTCREATEX_DISP_OPEN, break_to_none);
1844 * if it's a sharing violation or we got no oplock
1845 * only keep the lock if the caller requested access
1848 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1849 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1855 } else if (!NT_STATUS_IS_OK(status)) {
1868 determine if file meta data can be accessed, or if it is prevented by an
1871 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1872 struct ntvfs_request *req,
1873 struct pvfs_filename *name)
1877 struct odb_lock *lck;
1878 uint32_t share_access;
1879 uint32_t access_mask;
1880 bool delete_on_close;
1882 status = pvfs_locking_key(name, name, &key);
1883 if (!NT_STATUS_IS_OK(status)) {
1884 return NT_STATUS_NO_MEMORY;
1887 lck = odb_lock(req, pvfs->odb_context, &key);
1889 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1890 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1893 share_access = NTCREATEX_SHARE_ACCESS_READ |
1894 NTCREATEX_SHARE_ACCESS_WRITE;
1895 access_mask = SEC_FILE_READ_ATTRIBUTE;
1896 delete_on_close = false;
1898 status = odb_can_open(lck, name->stream_id,
1899 share_access, access_mask, delete_on_close,
1900 NTCREATEX_DISP_OPEN, false);
1902 if (!NT_STATUS_IS_OK(status)) {
1911 determine if delete on close is set on
1913 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1918 status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key,
1920 if (!NT_STATUS_IS_OK(status)) {
1921 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1925 return del_on_close;