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,
109 struct security_descriptor *sd;
111 /* setup any EAs that were asked for */
112 if (io->ntcreatex.in.ea_list) {
113 status = pvfs_setfileinfo_ea_set(pvfs, name, fd,
114 io->ntcreatex.in.ea_list->num_eas,
115 io->ntcreatex.in.ea_list->eas);
116 if (!NT_STATUS_IS_OK(status)) {
121 sd = io->ntcreatex.in.sec_desc;
122 /* setup an initial sec_desc if requested */
123 if (sd && (sd->type & SEC_DESC_DACL_PRESENT)) {
124 union smb_setfileinfo set;
126 * TODO: set the full ACL!
127 * - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
128 * when a SACL is present on the sd,
129 * but the user doesn't have SeSecurityPrivilege
132 set.set_secdesc.in.file.ntvfs = f->ntvfs;
133 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
134 set.set_secdesc.in.sd = sd;
136 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
138 /* otherwise setup an inherited acl from the parent */
139 status = pvfs_acl_inherit(pvfs, req, name, fd);
146 form the lock context used for opendb locking. Note that we must
147 zero here to take account of possible padding on some architectures
149 NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
150 TALLOC_CTX *mem_ctx, DATA_BLOB *key)
156 ZERO_STRUCT(lock_context);
158 lock_context.device = name->st.st_dev;
159 lock_context.inode = name->st.st_ino;
161 *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
162 if (key->data == NULL) {
163 return NT_STATUS_NO_MEMORY;
173 static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
174 struct ntvfs_request *req,
175 struct pvfs_filename *name,
179 struct ntvfs_handle *h;
181 uint32_t create_action;
182 uint32_t access_mask = io->generic.in.access_mask;
183 struct odb_lock *lck;
185 uint32_t create_options;
186 uint32_t share_access;
189 create_options = io->generic.in.create_options;
190 share_access = io->generic.in.share_access;
192 forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false;
194 if (name->stream_name) {
196 return NT_STATUS_NOT_A_DIRECTORY;
198 return NT_STATUS_FILE_IS_A_DIRECTORY;
202 /* if the client says it must be a directory, and it isn't,
204 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
205 return NT_STATUS_NOT_A_DIRECTORY;
208 /* found with gentest */
209 if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
210 (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
211 (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
212 return NT_STATUS_INVALID_PARAMETER;
215 switch (io->generic.in.open_disposition) {
216 case NTCREATEX_DISP_OPEN_IF:
219 case NTCREATEX_DISP_OPEN:
221 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
225 case NTCREATEX_DISP_CREATE:
227 return NT_STATUS_OBJECT_NAME_COLLISION;
231 case NTCREATEX_DISP_OVERWRITE_IF:
232 case NTCREATEX_DISP_OVERWRITE:
233 case NTCREATEX_DISP_SUPERSEDE:
235 return NT_STATUS_INVALID_PARAMETER;
238 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
239 NT_STATUS_NOT_OK_RETURN(status);
241 f = talloc(h, struct pvfs_file);
243 return NT_STATUS_NO_MEMORY;
246 f->handle = talloc(f, struct pvfs_file_handle);
247 if (f->handle == NULL) {
248 return NT_STATUS_NO_MEMORY;
252 /* check the security descriptor */
253 status = pvfs_access_check(pvfs, req, name, &access_mask);
255 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
257 NT_STATUS_NOT_OK_RETURN(status);
259 if (io->generic.in.query_maximal_access) {
260 status = pvfs_access_maximal_allowed(pvfs, req, name,
261 &io->generic.out.maximal_access);
262 NT_STATUS_NOT_OK_RETURN(status);
267 f->pending_list = NULL;
269 f->share_access = io->generic.in.share_access;
270 f->impersonation = io->generic.in.impersonation;
271 f->access_mask = access_mask;
272 f->brl_handle = NULL;
273 f->notify_buffer = NULL;
276 f->handle->pvfs = pvfs;
277 f->handle->name = talloc_steal(f->handle, name);
279 f->handle->odb_locking_key = data_blob(NULL, 0);
280 f->handle->create_options = io->generic.in.create_options;
281 f->handle->seek_offset = 0;
282 f->handle->position = 0;
284 f->handle->oplock = NULL;
285 ZERO_STRUCT(f->handle->write_time);
286 f->handle->open_completed = false;
288 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
289 pvfs_directory_empty(pvfs, f->handle->name)) {
292 del_on_close = false;
296 /* form the lock context used for opendb locking */
297 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
298 if (!NT_STATUS_IS_OK(status)) {
302 /* get a lock on this file before the actual open */
303 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
305 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
307 /* we were supposed to do a blocking lock, so something
309 return NT_STATUS_INTERNAL_DB_CORRUPTION;
312 /* see if we are allowed to open at the same time as existing opens */
313 status = odb_can_open(lck, name->stream_id,
314 share_access, access_mask, del_on_close,
315 io->generic.in.open_disposition, false);
316 if (!NT_STATUS_IS_OK(status)) {
321 /* now really mark the file as open */
322 status = odb_open_file(lck, f->handle, name->full_name,
323 NULL, name->dos.write_time,
324 false, OPLOCK_NONE, NULL);
326 if (!NT_STATUS_IS_OK(status)) {
331 f->handle->have_opendb_entry = true;
334 DLIST_ADD(pvfs->files.list, f);
336 /* setup destructors to avoid leaks on abnormal termination */
337 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
338 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
341 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
342 mode_t mode = pvfs_fileperms(pvfs, attrib);
344 if (mkdir(name->full_name, mode) == -1) {
345 return pvfs_map_errno(pvfs,errno);
348 pvfs_xattr_unlink_hook(pvfs, name->full_name);
350 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
351 if (!NT_STATUS_IS_OK(status)) {
355 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
356 if (!NT_STATUS_IS_OK(status)) {
360 /* form the lock context used for opendb locking */
361 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
362 if (!NT_STATUS_IS_OK(status)) {
366 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
368 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
370 /* we were supposed to do a blocking lock, so something
372 return NT_STATUS_INTERNAL_DB_CORRUPTION;
375 status = odb_can_open(lck, name->stream_id,
376 share_access, access_mask, del_on_close,
377 io->generic.in.open_disposition, false);
379 if (!NT_STATUS_IS_OK(status)) {
383 status = odb_open_file(lck, f->handle, name->full_name,
384 NULL, name->dos.write_time,
385 false, OPLOCK_NONE, NULL);
387 if (!NT_STATUS_IS_OK(status)) {
391 f->handle->have_opendb_entry = true;
393 create_action = NTCREATEX_ACTION_CREATED;
395 notify_trigger(pvfs->notify_context,
397 FILE_NOTIFY_CHANGE_DIR_NAME,
400 create_action = NTCREATEX_ACTION_EXISTED;
404 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
407 /* the open succeeded, keep this handle permanently */
408 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
409 if (!NT_STATUS_IS_OK(status)) {
413 f->handle->open_completed = true;
415 io->generic.out.oplock_level = OPLOCK_NONE;
416 io->generic.out.file.ntvfs = h;
417 io->generic.out.create_action = create_action;
418 io->generic.out.create_time = name->dos.create_time;
419 io->generic.out.access_time = name->dos.access_time;
420 io->generic.out.write_time = name->dos.write_time;
421 io->generic.out.change_time = name->dos.change_time;
422 io->generic.out.attrib = name->dos.attrib;
423 io->generic.out.alloc_size = name->dos.alloc_size;
424 io->generic.out.size = name->st.st_size;
425 io->generic.out.file_type = FILE_TYPE_DISK;
426 io->generic.out.ipc_state = 0;
427 io->generic.out.is_directory = 1;
432 rmdir(name->full_name);
437 destroy a struct pvfs_file_handle
439 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
441 talloc_free(h->write_time.update_event);
442 h->write_time.update_event = NULL;
444 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
445 h->name->stream_name) {
447 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
448 if (!NT_STATUS_IS_OK(status)) {
449 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
450 h->name->stream_name, h->name->full_name));
455 if (close(h->fd) != 0) {
456 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
457 h->fd, h->name->full_name, strerror(errno)));
462 if (!h->write_time.update_forced &&
463 h->write_time.update_on_close &&
464 h->write_time.close_time == 0) {
466 tv = timeval_current();
467 h->write_time.close_time = timeval_to_nttime(&tv);
470 if (h->have_opendb_entry) {
471 struct odb_lock *lck;
473 const char *delete_path = NULL;
475 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
477 DEBUG(0,("Unable to lock opendb for close\n"));
481 if (h->write_time.update_forced) {
482 status = odb_get_file_infos(h->pvfs->odb_context,
485 &h->write_time.close_time);
486 if (!NT_STATUS_IS_OK(status)) {
487 DEBUG(0,("Unable get write time for '%s' - %s\n",
488 h->name->full_name, nt_errstr(status)));
491 h->write_time.update_forced = false;
492 h->write_time.update_on_close = true;
493 } else if (h->write_time.update_on_close) {
494 status = odb_set_write_time(lck, h->write_time.close_time, true);
495 if (!NT_STATUS_IS_OK(status)) {
496 DEBUG(0,("Unable set write time for '%s' - %s\n",
497 h->name->full_name, nt_errstr(status)));
501 status = odb_close_file(lck, h, &delete_path);
502 if (!NT_STATUS_IS_OK(status)) {
503 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
504 h->name->full_name, nt_errstr(status)));
507 if (h->name->stream_name == NULL &&
508 h->open_completed && delete_path) {
509 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
510 if (!NT_STATUS_IS_OK(status)) {
511 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
512 delete_path, nt_errstr(status)));
514 if (unlink(delete_path) != 0) {
515 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
516 delete_path, strerror(errno)));
518 notify_trigger(h->pvfs->notify_context,
519 NOTIFY_ACTION_REMOVED,
520 FILE_NOTIFY_CHANGE_FILE_NAME,
523 h->write_time.update_on_close = false;
529 if (h->write_time.update_on_close) {
530 struct timeval tv[2];
532 nttime_to_timeval(&tv[0], h->name->dos.access_time);
533 nttime_to_timeval(&tv[1], h->write_time.close_time);
535 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
536 if (utimes(h->name->full_name, tv) == -1) {
537 DEBUG(0,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
538 h->name->full_name, strerror(errno)));
548 destroy a struct pvfs_file
550 static int pvfs_fnum_destructor(struct pvfs_file *f)
552 DLIST_REMOVE(f->pvfs->files.list, f);
553 pvfs_lock_close(f->pvfs, f);
554 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
561 form the lock context used for byte range locking. This is separate
562 from the locking key used for opendb locking as it needs to take
563 account of file streams (each stream is a separate byte range
566 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
567 struct pvfs_filename *name,
568 struct ntvfs_handle *ntvfs,
569 struct brl_handle **_h)
571 DATA_BLOB odb_key, key;
573 struct brl_handle *h;
575 status = pvfs_locking_key(name, mem_ctx, &odb_key);
576 NT_STATUS_NOT_OK_RETURN(status);
578 if (name->stream_name == NULL) {
581 key = data_blob_talloc(mem_ctx, NULL,
582 odb_key.length + strlen(name->stream_name) + 1);
583 NT_STATUS_HAVE_NO_MEMORY(key.data);
584 memcpy(key.data, odb_key.data, odb_key.length);
585 memcpy(key.data + odb_key.length,
586 name->stream_name, strlen(name->stream_name) + 1);
587 data_blob_free(&odb_key);
590 h = brl_create_handle(mem_ctx, ntvfs, &key);
591 NT_STATUS_HAVE_NO_MEMORY(h);
600 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
601 struct ntvfs_request *req,
602 struct pvfs_filename *name,
607 struct ntvfs_handle *h;
609 struct odb_lock *lck;
610 uint32_t create_options = io->generic.in.create_options;
611 uint32_t share_access = io->generic.in.share_access;
612 uint32_t access_mask = io->generic.in.access_mask;
616 struct pvfs_filename *parent;
617 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
618 bool allow_level_II_oplock = false;
620 if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
621 return NT_STATUS_INVALID_PARAMETER;
624 if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
625 return NT_STATUS_ACCESS_DENIED;
628 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
629 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
630 return NT_STATUS_CANNOT_DELETE;
633 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
634 NT_STATUS_NOT_OK_RETURN(status);
636 /* check that the parent isn't opened with delete on close set */
637 status = pvfs_resolve_parent(pvfs, req, name, &parent);
638 if (NT_STATUS_IS_OK(status)) {
639 DATA_BLOB locking_key;
640 status = pvfs_locking_key(parent, req, &locking_key);
641 NT_STATUS_NOT_OK_RETURN(status);
642 status = odb_get_file_infos(pvfs->odb_context, &locking_key,
643 &del_on_close, NULL);
644 NT_STATUS_NOT_OK_RETURN(status);
646 return NT_STATUS_DELETE_PENDING;
650 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
656 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
657 NT_STATUS_NOT_OK_RETURN(status);
659 f = talloc(h, struct pvfs_file);
660 NT_STATUS_HAVE_NO_MEMORY(f);
662 f->handle = talloc(f, struct pvfs_file_handle);
663 NT_STATUS_HAVE_NO_MEMORY(f->handle);
665 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
666 mode = pvfs_fileperms(pvfs, attrib);
668 /* create the file */
669 fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
671 return pvfs_map_errno(pvfs, errno);
674 pvfs_xattr_unlink_hook(pvfs, name->full_name);
676 /* if this was a stream create then create the stream as well */
677 if (name->stream_name) {
678 status = pvfs_stream_create(pvfs, name, fd);
679 if (!NT_STATUS_IS_OK(status)) {
685 /* re-resolve the open fd */
686 status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
687 if (!NT_STATUS_IS_OK(status)) {
692 /* support initial alloc sizes */
693 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
694 name->dos.attrib = attrib;
695 status = pvfs_dosattrib_save(pvfs, name, fd);
696 if (!NT_STATUS_IS_OK(status)) {
701 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
702 if (!NT_STATUS_IS_OK(status)) {
706 if (io->generic.in.query_maximal_access) {
707 status = pvfs_access_maximal_allowed(pvfs, req, name,
708 &io->generic.out.maximal_access);
709 NT_STATUS_NOT_OK_RETURN(status);
712 /* form the lock context used for byte range locking and
714 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
715 if (!NT_STATUS_IS_OK(status)) {
719 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
720 if (!NT_STATUS_IS_OK(status)) {
724 /* grab a lock on the open file record */
725 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
727 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
729 /* we were supposed to do a blocking lock, so something
731 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
735 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
738 del_on_close = false;
741 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
742 oplock_level = OPLOCK_NONE;
743 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
744 oplock_level = OPLOCK_BATCH;
745 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
746 oplock_level = OPLOCK_EXCLUSIVE;
749 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
750 allow_level_II_oplock = true;
753 status = odb_can_open(lck, name->stream_id,
754 share_access, access_mask, del_on_close,
755 io->generic.in.open_disposition, false);
756 if (!NT_STATUS_IS_OK(status)) {
758 /* bad news, we must have hit a race - we don't delete the file
759 here as the most likely scenario is that someone else created
760 the file at the same time */
767 f->pending_list = NULL;
769 f->share_access = io->generic.in.share_access;
770 f->access_mask = access_mask;
771 f->impersonation = io->generic.in.impersonation;
772 f->notify_buffer = NULL;
775 f->handle->pvfs = pvfs;
776 f->handle->name = talloc_steal(f->handle, name);
778 f->handle->create_options = io->generic.in.create_options;
779 f->handle->seek_offset = 0;
780 f->handle->position = 0;
782 f->handle->oplock = NULL;
783 f->handle->have_opendb_entry = true;
784 ZERO_STRUCT(f->handle->write_time);
785 f->handle->open_completed = false;
787 status = odb_open_file(lck, f->handle, name->full_name,
788 &f->handle->fd, name->dos.write_time,
789 allow_level_II_oplock,
790 oplock_level, &oplock_granted);
792 if (!NT_STATUS_IS_OK(status)) {
793 /* bad news, we must have hit a race - we don't delete the file
794 here as the most likely scenario is that someone else created
795 the file at the same time */
800 DLIST_ADD(pvfs->files.list, f);
802 /* setup a destructor to avoid file descriptor leaks on
803 abnormal termination */
804 talloc_set_destructor(f, pvfs_fnum_destructor);
805 talloc_set_destructor(f->handle, pvfs_handle_destructor);
807 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
808 oplock_granted = OPLOCK_BATCH;
809 } else if (oplock_granted != OPLOCK_NONE) {
810 status = pvfs_setup_oplock(f, oplock_granted);
811 if (!NT_STATUS_IS_OK(status)) {
816 io->generic.out.oplock_level = oplock_granted;
817 io->generic.out.file.ntvfs = f->ntvfs;
818 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
819 io->generic.out.create_time = name->dos.create_time;
820 io->generic.out.access_time = name->dos.access_time;
821 io->generic.out.write_time = name->dos.write_time;
822 io->generic.out.change_time = name->dos.change_time;
823 io->generic.out.attrib = name->dos.attrib;
824 io->generic.out.alloc_size = name->dos.alloc_size;
825 io->generic.out.size = name->st.st_size;
826 io->generic.out.file_type = FILE_TYPE_DISK;
827 io->generic.out.ipc_state = 0;
828 io->generic.out.is_directory = 0;
830 /* success - keep the file handle */
831 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
832 if (!NT_STATUS_IS_OK(status)) {
836 f->handle->open_completed = true;
838 notify_trigger(pvfs->notify_context,
840 FILE_NOTIFY_CHANGE_FILE_NAME,
847 unlink(name->full_name);
852 state of a pending retry
854 struct pvfs_odb_retry {
855 struct ntvfs_module_context *ntvfs;
856 struct ntvfs_request *req;
857 DATA_BLOB odb_locking_key;
860 void (*callback)(struct pvfs_odb_retry *r,
861 struct ntvfs_module_context *ntvfs,
862 struct ntvfs_request *req,
865 enum pvfs_wait_notice reason);
868 /* destroy a pending request */
869 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
871 struct pvfs_state *pvfs = r->ntvfs->private_data;
872 if (r->odb_locking_key.data) {
873 struct odb_lock *lck;
874 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
876 odb_remove_pending(lck, r);
883 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
885 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
887 if (reason == PVFS_WAIT_EVENT) {
889 * The pending odb entry is already removed.
890 * We use a null locking key to indicate this
893 data_blob_free(&r->odb_locking_key);
896 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
900 setup for a retry of a request that was rejected
903 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
904 struct ntvfs_request *req,
905 struct odb_lock *lck,
906 struct timeval end_time,
909 void (*callback)(struct pvfs_odb_retry *r,
910 struct ntvfs_module_context *ntvfs,
911 struct ntvfs_request *req,
914 enum pvfs_wait_notice reason))
916 struct pvfs_state *pvfs = ntvfs->private_data;
917 struct pvfs_odb_retry *r;
918 struct pvfs_wait *wait_handle;
921 r = talloc(req, struct pvfs_odb_retry);
922 NT_STATUS_HAVE_NO_MEMORY(r);
927 r->private_data = private_data;
928 r->callback = callback;
929 r->odb_locking_key = odb_get_key(r, lck);
930 if (r->odb_locking_key.data == NULL) {
931 return NT_STATUS_NO_MEMORY;
934 /* setup a pending lock */
935 status = odb_open_file_pending(lck, r);
936 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
938 * maybe only a unix application
941 data_blob_free(&r->odb_locking_key);
942 } else if (!NT_STATUS_IS_OK(status)) {
948 talloc_set_destructor(r, pvfs_odb_retry_destructor);
950 wait_handle = pvfs_wait_message(pvfs, req,
951 MSG_PVFS_RETRY_OPEN, end_time,
952 pvfs_odb_retry_callback, r);
953 if (wait_handle == NULL) {
954 return NT_STATUS_NO_MEMORY;
957 talloc_steal(r, wait_handle);
963 retry an open after a sharing violation
965 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
966 struct ntvfs_module_context *ntvfs,
967 struct ntvfs_request *req,
970 enum pvfs_wait_notice reason)
972 union smb_open *io = talloc_get_type(_io, union smb_open);
973 struct timeval *final_timeout = NULL;
977 final_timeout = talloc_get_type(private_data,
981 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
982 just a bug in their server, but we better do the same */
983 if (reason == PVFS_WAIT_CANCEL) {
987 if (reason == PVFS_WAIT_TIMEOUT) {
989 !timeval_expired(final_timeout)) {
991 * we need to retry periodictly
992 * after an EAGAIN as there's
993 * no way the kernel tell us
994 * an oplock is released.
998 /* if it timed out, then give the failure
1001 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
1002 req->async_states->send_fn(req);
1009 /* try the open again, which could trigger another retry setup
1010 if it wants to, so we have to unmark the async flag so we
1011 will know if it does a second async reply */
1012 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
1014 status = pvfs_open(ntvfs, req, io);
1015 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
1016 /* the 2nd try also replied async, so we don't send
1021 /* re-mark it async, just in case someone up the chain does
1022 paranoid checking */
1023 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1025 /* send the reply up the chain */
1026 req->async_states->status = status;
1027 req->async_states->send_fn(req);
1032 special handling for openx DENY_DOS semantics
1034 This function attempts a reference open using an existing handle. If its allowed,
1035 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
1036 open processing continues.
1038 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
1039 struct ntvfs_request *req, union smb_open *io,
1040 struct pvfs_file *f, struct odb_lock *lck)
1042 struct pvfs_state *pvfs = ntvfs->private_data;
1043 struct pvfs_file *f2;
1044 struct pvfs_filename *name;
1047 /* search for an existing open with the right parameters. Note
1048 the magic ntcreatex options flag, which is set in the
1049 generic mapping code. This might look ugly, but its
1050 actually pretty much now w2k does it internally as well.
1052 If you look at the BASE-DENYDOS test you will see that a
1053 DENY_DOS is a very special case, and in the right
1054 circumstances you actually get the _same_ handle back
1055 twice, rather than a new handle.
1057 for (f2=pvfs->files.list;f2;f2=f2->next) {
1059 f2->ntvfs->session_info == req->session_info &&
1060 f2->ntvfs->smbpid == req->smbpid &&
1061 (f2->handle->create_options &
1062 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
1063 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
1064 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1065 strcasecmp_m(f2->handle->name->original_name,
1066 io->generic.in.fname)==0) {
1072 return NT_STATUS_SHARING_VIOLATION;
1075 /* quite an insane set of semantics ... */
1076 if (is_exe_filename(io->generic.in.fname) &&
1077 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1078 return NT_STATUS_SHARING_VIOLATION;
1082 setup a reference to the existing handle
1084 talloc_free(f->handle);
1085 f->handle = talloc_reference(f, f2->handle);
1089 name = f->handle->name;
1091 io->generic.out.oplock_level = OPLOCK_NONE;
1092 io->generic.out.file.ntvfs = f->ntvfs;
1093 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1094 io->generic.out.create_time = name->dos.create_time;
1095 io->generic.out.access_time = name->dos.access_time;
1096 io->generic.out.write_time = name->dos.write_time;
1097 io->generic.out.change_time = name->dos.change_time;
1098 io->generic.out.attrib = name->dos.attrib;
1099 io->generic.out.alloc_size = name->dos.alloc_size;
1100 io->generic.out.size = name->st.st_size;
1101 io->generic.out.file_type = FILE_TYPE_DISK;
1102 io->generic.out.ipc_state = 0;
1103 io->generic.out.is_directory = 0;
1105 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1106 NT_STATUS_NOT_OK_RETURN(status);
1108 return NT_STATUS_OK;
1114 setup for a open retry after a sharing violation
1116 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1117 struct ntvfs_request *req,
1119 struct pvfs_file *f,
1120 struct odb_lock *lck,
1121 NTSTATUS parent_status)
1123 struct pvfs_state *pvfs = ntvfs->private_data;
1125 struct timeval end_time;
1126 struct timeval *final_timeout = NULL;
1128 if (io->generic.in.create_options &
1129 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1130 /* see if we can satisfy the request using the special DENY_DOS
1132 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1133 if (NT_STATUS_IS_OK(status)) {
1138 /* the retry should allocate a new file handle */
1141 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1142 end_time = timeval_add(&req->statistics.request_time,
1143 0, pvfs->sharing_violation_delay);
1144 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1145 end_time = timeval_add(&req->statistics.request_time,
1146 pvfs->oplock_break_timeout, 0);
1147 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1149 * we got EAGAIN which means a unix application
1150 * has an oplock or share mode
1152 * we retry every 4/5 of the sharing violation delay
1153 * to see if the unix application
1154 * has released the oplock or share mode.
1156 final_timeout = talloc(req, struct timeval);
1157 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1158 *final_timeout = timeval_add(&req->statistics.request_time,
1159 pvfs->oplock_break_timeout,
1161 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1162 end_time = timeval_min(final_timeout, &end_time);
1164 return NT_STATUS_INTERNAL_ERROR;
1167 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1168 final_timeout, pvfs_retry_open_sharing);
1174 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1175 struct ntvfs_request *req, union smb_open *io)
1177 struct pvfs_state *pvfs = ntvfs->private_data;
1179 struct pvfs_filename *name;
1180 struct pvfs_file *f;
1181 struct ntvfs_handle *h;
1184 struct odb_lock *lck;
1185 uint32_t create_options;
1186 uint32_t create_options_must_ignore_mask;
1187 uint32_t share_access;
1188 uint32_t access_mask;
1189 uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1191 bool stream_existed, stream_truncate=false;
1192 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1193 bool allow_level_II_oplock = false;
1195 /* use the generic mapping code to avoid implementing all the
1196 different open calls. */
1197 if (io->generic.level != RAW_OPEN_GENERIC &&
1198 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1199 return ntvfs_map_open(ntvfs, req, io);
1202 ZERO_STRUCT(io->generic.out);
1204 create_options = io->generic.in.create_options;
1205 share_access = io->generic.in.share_access;
1206 access_mask = io->generic.in.access_mask;
1208 if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1209 return NT_STATUS_INVALID_PARAMETER;
1213 * These options are ignored,
1214 * but we reuse some of them as private values for the generic mapping
1216 create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
1217 create_options_must_ignore_mask &= ~NTCREATEX_OPTIONS_PRIVATE_MASK;
1218 create_options &= ~create_options_must_ignore_mask;
1220 if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1221 DEBUG(2,(__location__ " create_options 0x%x not supported\n",
1223 return NT_STATUS_NOT_SUPPORTED;
1226 if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
1227 return NT_STATUS_INVALID_PARAMETER;
1230 /* TODO: When we implement HSM, add a hook here not to pull
1231 * the actual file off tape, when this option is passed from
1233 if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1237 /* TODO: If (unlikely) Linux does a good compressed
1238 * filesystem, we might need an ioctl call for this */
1239 if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
1243 if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
1244 create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
1247 /* Open the file with sync, if they asked for it, but
1248 'strict sync = no' turns this client request into a no-op */
1249 if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && !(pvfs->flags | PVFS_FLAG_STRICT_SYNC)) {
1254 /* other create options are not allowed */
1255 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1256 !(access_mask & SEC_STD_DELETE)) {
1257 return NT_STATUS_INVALID_PARAMETER;
1260 if (access_mask & SEC_MASK_INVALID) {
1261 return NT_STATUS_ACCESS_DENIED;
1264 /* what does this bit really mean?? */
1265 if (req->ctx->protocol == PROTOCOL_SMB2 &&
1266 access_mask == SEC_STD_SYNCHRONIZE) {
1267 return NT_STATUS_ACCESS_DENIED;
1270 if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1271 FILE_ATTRIBUTE_VOLUME|
1272 (~FILE_ATTRIBUTE_ALL_MASK))) {
1273 return NT_STATUS_INVALID_PARAMETER;
1276 /* we ignore some file_attr bits */
1277 io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED |
1278 FILE_ATTRIBUTE_COMPRESSED |
1279 FILE_ATTRIBUTE_REPARSE_POINT |
1280 FILE_ATTRIBUTE_SPARSE |
1281 FILE_ATTRIBUTE_NORMAL);
1283 /* resolve the cifs name to a posix name */
1284 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1285 PVFS_RESOLVE_STREAMS, &name);
1286 if (!NT_STATUS_IS_OK(status)) {
1290 /* if the client specified that it must not be a directory then
1291 check that it isn't */
1292 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1293 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1294 return NT_STATUS_FILE_IS_A_DIRECTORY;
1297 /* if the client specified that it must be a directory then
1299 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1300 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1301 return NT_STATUS_NOT_A_DIRECTORY;
1304 /* directory opens are handled separately */
1305 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1306 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1307 return pvfs_open_directory(pvfs, req, name, io);
1310 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1311 open doesn't match */
1312 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1314 switch (io->generic.in.open_disposition) {
1315 case NTCREATEX_DISP_SUPERSEDE:
1316 case NTCREATEX_DISP_OVERWRITE_IF:
1317 if (name->stream_name == NULL) {
1320 stream_truncate = true;
1322 create_action = NTCREATEX_ACTION_TRUNCATED;
1325 case NTCREATEX_DISP_OPEN:
1326 if (!name->stream_exists) {
1327 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1332 case NTCREATEX_DISP_OVERWRITE:
1333 if (!name->stream_exists) {
1334 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1336 if (name->stream_name == NULL) {
1339 stream_truncate = true;
1341 create_action = NTCREATEX_ACTION_TRUNCATED;
1344 case NTCREATEX_DISP_CREATE:
1345 if (name->stream_exists) {
1346 return NT_STATUS_OBJECT_NAME_COLLISION;
1351 case NTCREATEX_DISP_OPEN_IF:
1356 return NT_STATUS_INVALID_PARAMETER;
1359 /* handle creating a new file separately */
1360 if (!name->exists) {
1361 status = pvfs_create_file(pvfs, req, name, io);
1362 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1366 /* we've hit a race - the file was created during this call */
1367 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1371 /* try re-resolving the name */
1372 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1373 if (!NT_STATUS_IS_OK(status)) {
1376 /* fall through to a normal open */
1379 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1380 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1381 return NT_STATUS_CANNOT_DELETE;
1384 /* check the security descriptor */
1385 status = pvfs_access_check(pvfs, req, name, &access_mask);
1386 NT_STATUS_NOT_OK_RETURN(status);
1388 if (io->generic.in.query_maximal_access) {
1389 status = pvfs_access_maximal_allowed(pvfs, req, name,
1390 &io->generic.out.maximal_access);
1391 NT_STATUS_NOT_OK_RETURN(status);
1394 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1395 NT_STATUS_NOT_OK_RETURN(status);
1397 f = talloc(h, struct pvfs_file);
1399 return NT_STATUS_NO_MEMORY;
1402 f->handle = talloc(f, struct pvfs_file_handle);
1403 if (f->handle == NULL) {
1404 return NT_STATUS_NO_MEMORY;
1409 f->pending_list = NULL;
1411 f->share_access = io->generic.in.share_access;
1412 f->access_mask = access_mask;
1413 f->impersonation = io->generic.in.impersonation;
1414 f->notify_buffer = NULL;
1417 f->handle->pvfs = pvfs;
1419 f->handle->name = talloc_steal(f->handle, name);
1420 f->handle->create_options = io->generic.in.create_options;
1421 f->handle->seek_offset = 0;
1422 f->handle->position = 0;
1423 f->handle->mode = 0;
1424 f->handle->oplock = NULL;
1425 f->handle->have_opendb_entry = false;
1426 ZERO_STRUCT(f->handle->write_time);
1427 f->handle->open_completed = false;
1429 /* form the lock context used for byte range locking and
1431 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1432 if (!NT_STATUS_IS_OK(status)) {
1436 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1437 if (!NT_STATUS_IS_OK(status)) {
1441 /* get a lock on this file before the actual open */
1442 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1444 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1446 /* we were supposed to do a blocking lock, so something
1448 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1451 DLIST_ADD(pvfs->files.list, f);
1453 /* setup a destructor to avoid file descriptor leaks on
1454 abnormal termination */
1455 talloc_set_destructor(f, pvfs_fnum_destructor);
1456 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1459 * Only SMB2 takes care of the delete_on_close,
1462 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1463 req->ctx->protocol == PROTOCOL_SMB2) {
1464 del_on_close = true;
1466 del_on_close = false;
1469 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1470 oplock_level = OPLOCK_NONE;
1471 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1472 oplock_level = OPLOCK_BATCH;
1473 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1474 oplock_level = OPLOCK_EXCLUSIVE;
1477 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1478 allow_level_II_oplock = true;
1481 /* see if we are allowed to open at the same time as existing opens */
1482 status = odb_can_open(lck, name->stream_id,
1483 share_access, access_mask, del_on_close,
1484 io->generic.in.open_disposition, false);
1487 * on a sharing violation we need to retry when the file is closed by
1488 * the other user, or after 1 second
1489 * on a non granted oplock we need to retry when the file is closed by
1490 * the other user, or after 30 seconds
1492 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1493 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1494 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1495 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1498 if (!NT_STATUS_IS_OK(status)) {
1503 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1509 /* do the actual open */
1510 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1512 status = pvfs_map_errno(f->pvfs, errno);
1515 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1517 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1518 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1519 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1528 /* now really mark the file as open */
1529 status = odb_open_file(lck, f->handle, name->full_name,
1530 &f->handle->fd, name->dos.write_time,
1531 allow_level_II_oplock,
1532 oplock_level, &oplock_granted);
1534 if (!NT_STATUS_IS_OK(status)) {
1539 f->handle->have_opendb_entry = true;
1541 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1542 oplock_granted = OPLOCK_BATCH;
1543 } else if (oplock_granted != OPLOCK_NONE) {
1544 status = pvfs_setup_oplock(f, oplock_granted);
1545 if (!NT_STATUS_IS_OK(status)) {
1551 stream_existed = name->stream_exists;
1553 /* if this was a stream create then create the stream as well */
1554 if (!name->stream_exists) {
1555 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1556 if (!NT_STATUS_IS_OK(status)) {
1560 if (stream_truncate) {
1561 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1562 if (!NT_STATUS_IS_OK(status)) {
1569 /* re-resolve the open fd */
1570 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1571 if (!NT_STATUS_IS_OK(status)) {
1576 if (f->handle->name->stream_id == 0 &&
1577 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1578 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1579 /* for overwrite we need to replace file permissions */
1580 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1581 mode_t mode = pvfs_fileperms(pvfs, attrib);
1582 if (fchmod(fd, mode) == -1) {
1584 return pvfs_map_errno(pvfs, errno);
1586 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1587 name->dos.attrib = attrib;
1588 status = pvfs_dosattrib_save(pvfs, name, fd);
1589 if (!NT_STATUS_IS_OK(status)) {
1597 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1598 NT_STATUS_NOT_OK_RETURN(status);
1600 /* mark the open as having completed fully, so delete on close
1602 f->handle->open_completed = true;
1604 io->generic.out.oplock_level = oplock_granted;
1605 io->generic.out.file.ntvfs = h;
1606 io->generic.out.create_action = stream_existed?
1607 create_action:NTCREATEX_ACTION_CREATED;
1609 io->generic.out.create_time = name->dos.create_time;
1610 io->generic.out.access_time = name->dos.access_time;
1611 io->generic.out.write_time = name->dos.write_time;
1612 io->generic.out.change_time = name->dos.change_time;
1613 io->generic.out.attrib = name->dos.attrib;
1614 io->generic.out.alloc_size = name->dos.alloc_size;
1615 io->generic.out.size = name->st.st_size;
1616 io->generic.out.file_type = FILE_TYPE_DISK;
1617 io->generic.out.ipc_state = 0;
1618 io->generic.out.is_directory = 0;
1620 return NT_STATUS_OK;
1627 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1628 struct ntvfs_request *req, union smb_close *io)
1630 struct pvfs_state *pvfs = ntvfs->private_data;
1631 struct pvfs_file *f;
1633 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1634 return NT_STATUS_DOS(ERRSRV, ERRerror);
1637 if (io->generic.level != RAW_CLOSE_GENERIC) {
1638 return ntvfs_map_close(ntvfs, req, io);
1641 f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1643 return NT_STATUS_INVALID_HANDLE;
1646 if (!null_time(io->generic.in.write_time)) {
1647 f->handle->write_time.update_forced = false;
1648 f->handle->write_time.update_on_close = true;
1649 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1652 if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1653 struct pvfs_filename *name;
1655 struct pvfs_file_handle *h = f->handle;
1657 status = pvfs_resolve_name_handle(pvfs, h);
1658 if (!NT_STATUS_IS_OK(status)) {
1663 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1664 io->generic.out.create_time = name->dos.create_time;
1665 io->generic.out.access_time = name->dos.access_time;
1666 io->generic.out.write_time = name->dos.write_time;
1667 io->generic.out.change_time = name->dos.change_time;
1668 io->generic.out.alloc_size = name->dos.alloc_size;
1669 io->generic.out.size = name->st.st_size;
1670 io->generic.out.file_attr = name->dos.attrib;
1672 ZERO_STRUCT(io->generic.out);
1677 return NT_STATUS_OK;
1682 logoff - close all file descriptors open by a vuid
1684 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1685 struct ntvfs_request *req)
1687 struct pvfs_state *pvfs = ntvfs->private_data;
1688 struct pvfs_file *f, *next;
1690 for (f=pvfs->files.list;f;f=next) {
1692 if (f->ntvfs->session_info == req->session_info) {
1697 return NT_STATUS_OK;
1702 exit - close files for the current pid
1704 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1705 struct ntvfs_request *req)
1707 struct pvfs_state *pvfs = ntvfs->private_data;
1708 struct pvfs_file *f, *next;
1710 for (f=pvfs->files.list;f;f=next) {
1712 if (f->ntvfs->session_info == req->session_info &&
1713 f->ntvfs->smbpid == req->smbpid) {
1718 return NT_STATUS_OK;
1723 change the delete on close flag on an already open file
1725 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1726 struct ntvfs_request *req,
1727 struct pvfs_file *f, bool del_on_close)
1729 struct odb_lock *lck;
1732 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1733 return NT_STATUS_CANNOT_DELETE;
1736 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1737 !pvfs_directory_empty(pvfs, f->handle->name)) {
1738 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1742 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1744 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1747 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1749 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1752 status = odb_set_delete_on_close(lck, del_on_close);
1761 determine if a file can be deleted, or if it is prevented by an
1764 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1765 struct ntvfs_request *req,
1766 struct pvfs_filename *name,
1767 struct odb_lock **lckp)
1771 struct odb_lock *lck;
1772 uint32_t share_access;
1773 uint32_t access_mask;
1774 bool delete_on_close;
1776 status = pvfs_locking_key(name, name, &key);
1777 if (!NT_STATUS_IS_OK(status)) {
1778 return NT_STATUS_NO_MEMORY;
1781 lck = odb_lock(req, pvfs->odb_context, &key);
1783 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1784 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1787 share_access = NTCREATEX_SHARE_ACCESS_READ |
1788 NTCREATEX_SHARE_ACCESS_WRITE |
1789 NTCREATEX_SHARE_ACCESS_DELETE;
1790 access_mask = SEC_STD_DELETE;
1791 delete_on_close = true;
1793 status = odb_can_open(lck, name->stream_id,
1794 share_access, access_mask, delete_on_close,
1795 NTCREATEX_DISP_OPEN, false);
1797 if (NT_STATUS_IS_OK(status)) {
1798 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1802 * if it's a sharing violation or we got no oplock
1803 * only keep the lock if the caller requested access
1806 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1807 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1813 } else if (!NT_STATUS_IS_OK(status)) {
1826 determine if a file can be renamed, or if it is prevented by an
1829 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1830 struct ntvfs_request *req,
1831 struct pvfs_filename *name,
1832 struct odb_lock **lckp)
1836 struct odb_lock *lck;
1837 uint32_t share_access;
1838 uint32_t access_mask;
1839 bool delete_on_close;
1841 status = pvfs_locking_key(name, name, &key);
1842 if (!NT_STATUS_IS_OK(status)) {
1843 return NT_STATUS_NO_MEMORY;
1846 lck = odb_lock(req, pvfs->odb_context, &key);
1848 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1849 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1852 share_access = NTCREATEX_SHARE_ACCESS_READ |
1853 NTCREATEX_SHARE_ACCESS_WRITE;
1854 access_mask = SEC_STD_DELETE;
1855 delete_on_close = false;
1857 status = odb_can_open(lck, name->stream_id,
1858 share_access, access_mask, delete_on_close,
1859 NTCREATEX_DISP_OPEN, false);
1862 * if it's a sharing violation or we got no oplock
1863 * only keep the lock if the caller requested access
1866 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1867 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1873 } else if (!NT_STATUS_IS_OK(status)) {
1886 determine if the file size of a file can be changed,
1887 or if it is prevented by an already open file
1889 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1890 struct ntvfs_request *req,
1891 struct pvfs_filename *name,
1892 struct odb_lock **lckp)
1896 struct odb_lock *lck;
1897 uint32_t share_access;
1898 uint32_t access_mask;
1900 bool delete_on_close;
1902 status = pvfs_locking_key(name, name, &key);
1903 if (!NT_STATUS_IS_OK(status)) {
1904 return NT_STATUS_NO_MEMORY;
1907 lck = odb_lock(req, pvfs->odb_context, &key);
1909 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1910 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1913 share_access = NTCREATEX_SHARE_ACCESS_READ |
1914 NTCREATEX_SHARE_ACCESS_WRITE |
1915 NTCREATEX_SHARE_ACCESS_DELETE;
1917 * I would have thought that we would need to pass
1918 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1920 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1921 * to set the filesize.
1925 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1926 delete_on_close = false;
1927 break_to_none = true;
1929 status = odb_can_open(lck, name->stream_id,
1930 share_access, access_mask, delete_on_close,
1931 NTCREATEX_DISP_OPEN, break_to_none);
1934 * if it's a sharing violation or we got no oplock
1935 * only keep the lock if the caller requested access
1938 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1939 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1945 } else if (!NT_STATUS_IS_OK(status)) {
1958 determine if file meta data can be accessed, or if it is prevented by an
1961 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1962 struct ntvfs_request *req,
1963 struct pvfs_filename *name)
1967 struct odb_lock *lck;
1968 uint32_t share_access;
1969 uint32_t access_mask;
1970 bool delete_on_close;
1972 status = pvfs_locking_key(name, name, &key);
1973 if (!NT_STATUS_IS_OK(status)) {
1974 return NT_STATUS_NO_MEMORY;
1977 lck = odb_lock(req, pvfs->odb_context, &key);
1979 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1980 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1983 share_access = NTCREATEX_SHARE_ACCESS_READ |
1984 NTCREATEX_SHARE_ACCESS_WRITE;
1985 access_mask = SEC_FILE_READ_ATTRIBUTE;
1986 delete_on_close = false;
1988 status = odb_can_open(lck, name->stream_id,
1989 share_access, access_mask, delete_on_close,
1990 NTCREATEX_DISP_OPEN, false);
1992 if (!NT_STATUS_IS_OK(status)) {
2001 determine if delete on close is set on
2003 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
2008 status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key,
2009 &del_on_close, NULL);
2010 if (!NT_STATUS_IS_OK(status)) {
2011 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2015 return del_on_close;