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 ZERO_STRUCT(f->handle->write_time);
284 f->handle->open_completed = false;
286 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
287 pvfs_directory_empty(pvfs, f->handle->name)) {
290 del_on_close = false;
294 /* form the lock context used for opendb locking */
295 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
296 if (!NT_STATUS_IS_OK(status)) {
300 /* get a lock on this file before the actual open */
301 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
303 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
305 /* we were supposed to do a blocking lock, so something
307 return NT_STATUS_INTERNAL_DB_CORRUPTION;
310 /* see if we are allowed to open at the same time as existing opens */
311 status = odb_can_open(lck, name->stream_id,
312 share_access, access_mask, del_on_close,
313 io->generic.in.open_disposition, false);
314 if (!NT_STATUS_IS_OK(status)) {
319 /* now really mark the file as open */
320 status = odb_open_file(lck, f->handle, name->full_name,
321 NULL, name->dos.write_time,
322 false, OPLOCK_NONE, NULL);
324 if (!NT_STATUS_IS_OK(status)) {
329 f->handle->have_opendb_entry = true;
332 DLIST_ADD(pvfs->files.list, f);
334 /* setup destructors to avoid leaks on abnormal termination */
335 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
336 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
339 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
340 mode_t mode = pvfs_fileperms(pvfs, attrib);
342 if (mkdir(name->full_name, mode) == -1) {
343 return pvfs_map_errno(pvfs,errno);
346 pvfs_xattr_unlink_hook(pvfs, name->full_name);
348 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
349 if (!NT_STATUS_IS_OK(status)) {
353 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
354 if (!NT_STATUS_IS_OK(status)) {
358 /* form the lock context used for opendb locking */
359 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
360 if (!NT_STATUS_IS_OK(status)) {
364 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
366 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
368 /* we were supposed to do a blocking lock, so something
370 return NT_STATUS_INTERNAL_DB_CORRUPTION;
373 status = odb_can_open(lck, name->stream_id,
374 share_access, access_mask, del_on_close,
375 io->generic.in.open_disposition, false);
377 if (!NT_STATUS_IS_OK(status)) {
381 status = odb_open_file(lck, f->handle, name->full_name,
382 NULL, name->dos.write_time,
383 false, OPLOCK_NONE, NULL);
385 if (!NT_STATUS_IS_OK(status)) {
389 f->handle->have_opendb_entry = true;
391 create_action = NTCREATEX_ACTION_CREATED;
393 notify_trigger(pvfs->notify_context,
395 FILE_NOTIFY_CHANGE_DIR_NAME,
398 create_action = NTCREATEX_ACTION_EXISTED;
402 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
405 /* the open succeeded, keep this handle permanently */
406 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
407 if (!NT_STATUS_IS_OK(status)) {
411 f->handle->open_completed = true;
413 io->generic.out.oplock_level = OPLOCK_NONE;
414 io->generic.out.file.ntvfs = h;
415 io->generic.out.create_action = create_action;
416 io->generic.out.create_time = name->dos.create_time;
417 io->generic.out.access_time = name->dos.access_time;
418 io->generic.out.write_time = name->dos.write_time;
419 io->generic.out.change_time = name->dos.change_time;
420 io->generic.out.attrib = name->dos.attrib;
421 io->generic.out.alloc_size = name->dos.alloc_size;
422 io->generic.out.size = name->st.st_size;
423 io->generic.out.file_type = FILE_TYPE_DISK;
424 io->generic.out.ipc_state = 0;
425 io->generic.out.is_directory = 1;
430 rmdir(name->full_name);
435 destroy a struct pvfs_file_handle
437 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
439 talloc_free(h->write_time.update_event);
440 h->write_time.update_event = NULL;
442 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
443 h->name->stream_name) {
445 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
446 if (!NT_STATUS_IS_OK(status)) {
447 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
448 h->name->stream_name, h->name->full_name));
453 if (close(h->fd) != 0) {
454 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
455 h->fd, h->name->full_name, strerror(errno)));
460 if (!h->write_time.update_forced &&
461 h->write_time.update_on_close &&
462 h->write_time.close_time == 0) {
464 tv = timeval_current();
465 h->write_time.close_time = timeval_to_nttime(&tv);
468 if (h->have_opendb_entry) {
469 struct odb_lock *lck;
471 const char *delete_path = NULL;
473 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
475 DEBUG(0,("Unable to lock opendb for close\n"));
479 if (h->write_time.update_forced) {
480 status = odb_get_file_infos(h->pvfs->odb_context,
483 &h->write_time.close_time);
484 if (!NT_STATUS_IS_OK(status)) {
485 DEBUG(0,("Unable get write time for '%s' - %s\n",
486 h->name->full_name, nt_errstr(status)));
489 h->write_time.update_forced = false;
490 h->write_time.update_on_close = true;
491 } else if (h->write_time.update_on_close) {
492 status = odb_set_write_time(lck, h->write_time.close_time, true);
493 if (!NT_STATUS_IS_OK(status)) {
494 DEBUG(0,("Unable set write time for '%s' - %s\n",
495 h->name->full_name, nt_errstr(status)));
499 status = odb_close_file(lck, h, &delete_path);
500 if (!NT_STATUS_IS_OK(status)) {
501 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
502 h->name->full_name, nt_errstr(status)));
505 if (h->name->stream_name == NULL &&
506 h->open_completed && delete_path) {
507 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
508 if (!NT_STATUS_IS_OK(status)) {
509 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
510 delete_path, nt_errstr(status)));
512 if (unlink(delete_path) != 0) {
513 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
514 delete_path, strerror(errno)));
516 notify_trigger(h->pvfs->notify_context,
517 NOTIFY_ACTION_REMOVED,
518 FILE_NOTIFY_CHANGE_FILE_NAME,
521 h->write_time.update_on_close = false;
527 if (h->write_time.update_on_close) {
528 struct timeval tv[2];
530 nttime_to_timeval(&tv[0], h->name->dos.access_time);
531 nttime_to_timeval(&tv[1], h->write_time.close_time);
533 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
534 if (utimes(h->name->full_name, tv) == -1) {
535 DEBUG(0,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
536 h->name->full_name, strerror(errno)));
546 destroy a struct pvfs_file
548 static int pvfs_fnum_destructor(struct pvfs_file *f)
550 DLIST_REMOVE(f->pvfs->files.list, f);
551 pvfs_lock_close(f->pvfs, f);
552 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
559 form the lock context used for byte range locking. This is separate
560 from the locking key used for opendb locking as it needs to take
561 account of file streams (each stream is a separate byte range
564 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
565 struct pvfs_filename *name,
566 struct ntvfs_handle *ntvfs,
567 struct brl_handle **_h)
569 DATA_BLOB odb_key, key;
571 struct brl_handle *h;
573 status = pvfs_locking_key(name, mem_ctx, &odb_key);
574 NT_STATUS_NOT_OK_RETURN(status);
576 if (name->stream_name == NULL) {
579 key = data_blob_talloc(mem_ctx, NULL,
580 odb_key.length + strlen(name->stream_name) + 1);
581 NT_STATUS_HAVE_NO_MEMORY(key.data);
582 memcpy(key.data, odb_key.data, odb_key.length);
583 memcpy(key.data + odb_key.length,
584 name->stream_name, strlen(name->stream_name) + 1);
585 data_blob_free(&odb_key);
588 h = brl_create_handle(mem_ctx, ntvfs, &key);
589 NT_STATUS_HAVE_NO_MEMORY(h);
598 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
599 struct ntvfs_request *req,
600 struct pvfs_filename *name,
605 struct ntvfs_handle *h;
607 struct odb_lock *lck;
608 uint32_t create_options = io->generic.in.create_options;
609 uint32_t share_access = io->generic.in.share_access;
610 uint32_t access_mask = io->generic.in.access_mask;
614 struct pvfs_filename *parent;
615 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
616 bool allow_level_II_oplock = false;
618 if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
619 return NT_STATUS_INVALID_PARAMETER;
622 if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
623 return NT_STATUS_ACCESS_DENIED;
626 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
627 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
628 return NT_STATUS_CANNOT_DELETE;
631 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
632 NT_STATUS_NOT_OK_RETURN(status);
634 if (io->generic.in.query_maximal_access) {
635 status = pvfs_access_maximal_allowed(pvfs, req, name,
636 &io->generic.out.maximal_access);
637 NT_STATUS_NOT_OK_RETURN(status);
640 /* check that the parent isn't opened with delete on close set */
641 status = pvfs_resolve_parent(pvfs, req, name, &parent);
642 if (NT_STATUS_IS_OK(status)) {
643 DATA_BLOB locking_key;
644 status = pvfs_locking_key(parent, req, &locking_key);
645 NT_STATUS_NOT_OK_RETURN(status);
646 status = odb_get_file_infos(pvfs->odb_context, &locking_key,
647 &del_on_close, NULL);
648 NT_STATUS_NOT_OK_RETURN(status);
650 return NT_STATUS_DELETE_PENDING;
654 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
660 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
661 NT_STATUS_NOT_OK_RETURN(status);
663 f = talloc(h, struct pvfs_file);
664 NT_STATUS_HAVE_NO_MEMORY(f);
666 f->handle = talloc(f, struct pvfs_file_handle);
667 NT_STATUS_HAVE_NO_MEMORY(f->handle);
669 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
670 mode = pvfs_fileperms(pvfs, attrib);
672 /* create the file */
673 fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
675 return pvfs_map_errno(pvfs, errno);
678 pvfs_xattr_unlink_hook(pvfs, name->full_name);
680 /* if this was a stream create then create the stream as well */
681 if (name->stream_name) {
682 status = pvfs_stream_create(pvfs, name, fd);
683 if (!NT_STATUS_IS_OK(status)) {
689 /* re-resolve the open fd */
690 status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
691 if (!NT_STATUS_IS_OK(status)) {
696 /* support initial alloc sizes */
697 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
698 name->dos.attrib = attrib;
699 status = pvfs_dosattrib_save(pvfs, name, fd);
700 if (!NT_STATUS_IS_OK(status)) {
705 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
706 if (!NT_STATUS_IS_OK(status)) {
710 /* form the lock context used for byte range locking and
712 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
713 if (!NT_STATUS_IS_OK(status)) {
717 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
718 if (!NT_STATUS_IS_OK(status)) {
722 /* grab a lock on the open file record */
723 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
725 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
727 /* we were supposed to do a blocking lock, so something
729 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
733 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
736 del_on_close = false;
739 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
740 oplock_level = OPLOCK_NONE;
741 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
742 oplock_level = OPLOCK_BATCH;
743 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
744 oplock_level = OPLOCK_EXCLUSIVE;
747 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
748 allow_level_II_oplock = true;
751 status = odb_can_open(lck, name->stream_id,
752 share_access, access_mask, del_on_close,
753 io->generic.in.open_disposition, false);
754 if (!NT_STATUS_IS_OK(status)) {
756 /* bad news, we must have hit a race - we don't delete the file
757 here as the most likely scenario is that someone else created
758 the file at the same time */
765 f->pending_list = NULL;
767 f->share_access = io->generic.in.share_access;
768 f->access_mask = access_mask;
769 f->impersonation = io->generic.in.impersonation;
770 f->notify_buffer = NULL;
773 f->handle->pvfs = pvfs;
774 f->handle->name = talloc_steal(f->handle, name);
776 f->handle->create_options = io->generic.in.create_options;
777 f->handle->seek_offset = 0;
778 f->handle->position = 0;
780 f->handle->oplock = NULL;
781 f->handle->have_opendb_entry = true;
782 ZERO_STRUCT(f->handle->write_time);
783 f->handle->open_completed = false;
785 status = odb_open_file(lck, f->handle, name->full_name,
786 &f->handle->fd, name->dos.write_time,
787 allow_level_II_oplock,
788 oplock_level, &oplock_granted);
790 if (!NT_STATUS_IS_OK(status)) {
791 /* bad news, we must have hit a race - we don't delete the file
792 here as the most likely scenario is that someone else created
793 the file at the same time */
798 DLIST_ADD(pvfs->files.list, f);
800 /* setup a destructor to avoid file descriptor leaks on
801 abnormal termination */
802 talloc_set_destructor(f, pvfs_fnum_destructor);
803 talloc_set_destructor(f->handle, pvfs_handle_destructor);
805 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
806 oplock_granted = OPLOCK_BATCH;
807 } else if (oplock_granted != OPLOCK_NONE) {
808 status = pvfs_setup_oplock(f, oplock_granted);
809 if (!NT_STATUS_IS_OK(status)) {
814 io->generic.out.oplock_level = oplock_granted;
815 io->generic.out.file.ntvfs = f->ntvfs;
816 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
817 io->generic.out.create_time = name->dos.create_time;
818 io->generic.out.access_time = name->dos.access_time;
819 io->generic.out.write_time = name->dos.write_time;
820 io->generic.out.change_time = name->dos.change_time;
821 io->generic.out.attrib = name->dos.attrib;
822 io->generic.out.alloc_size = name->dos.alloc_size;
823 io->generic.out.size = name->st.st_size;
824 io->generic.out.file_type = FILE_TYPE_DISK;
825 io->generic.out.ipc_state = 0;
826 io->generic.out.is_directory = 0;
828 /* success - keep the file handle */
829 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
830 if (!NT_STATUS_IS_OK(status)) {
834 f->handle->open_completed = true;
836 notify_trigger(pvfs->notify_context,
838 FILE_NOTIFY_CHANGE_FILE_NAME,
845 unlink(name->full_name);
850 state of a pending retry
852 struct pvfs_odb_retry {
853 struct ntvfs_module_context *ntvfs;
854 struct ntvfs_request *req;
855 DATA_BLOB odb_locking_key;
858 void (*callback)(struct pvfs_odb_retry *r,
859 struct ntvfs_module_context *ntvfs,
860 struct ntvfs_request *req,
863 enum pvfs_wait_notice reason);
866 /* destroy a pending request */
867 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
869 struct pvfs_state *pvfs = r->ntvfs->private_data;
870 if (r->odb_locking_key.data) {
871 struct odb_lock *lck;
872 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
874 odb_remove_pending(lck, r);
881 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
883 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
885 if (reason == PVFS_WAIT_EVENT) {
887 * The pending odb entry is already removed.
888 * We use a null locking key to indicate this
891 data_blob_free(&r->odb_locking_key);
894 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
898 setup for a retry of a request that was rejected
901 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
902 struct ntvfs_request *req,
903 struct odb_lock *lck,
904 struct timeval end_time,
907 void (*callback)(struct pvfs_odb_retry *r,
908 struct ntvfs_module_context *ntvfs,
909 struct ntvfs_request *req,
912 enum pvfs_wait_notice reason))
914 struct pvfs_state *pvfs = ntvfs->private_data;
915 struct pvfs_odb_retry *r;
916 struct pvfs_wait *wait_handle;
919 r = talloc(req, struct pvfs_odb_retry);
920 NT_STATUS_HAVE_NO_MEMORY(r);
925 r->private_data = private_data;
926 r->callback = callback;
927 r->odb_locking_key = odb_get_key(r, lck);
928 if (r->odb_locking_key.data == NULL) {
929 return NT_STATUS_NO_MEMORY;
932 /* setup a pending lock */
933 status = odb_open_file_pending(lck, r);
934 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
936 * maybe only a unix application
939 data_blob_free(&r->odb_locking_key);
940 } else if (!NT_STATUS_IS_OK(status)) {
946 talloc_set_destructor(r, pvfs_odb_retry_destructor);
948 wait_handle = pvfs_wait_message(pvfs, req,
949 MSG_PVFS_RETRY_OPEN, end_time,
950 pvfs_odb_retry_callback, r);
951 if (wait_handle == NULL) {
952 return NT_STATUS_NO_MEMORY;
955 talloc_steal(r, wait_handle);
961 retry an open after a sharing violation
963 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
964 struct ntvfs_module_context *ntvfs,
965 struct ntvfs_request *req,
968 enum pvfs_wait_notice reason)
970 union smb_open *io = talloc_get_type(_io, union smb_open);
971 struct timeval *final_timeout = NULL;
975 final_timeout = talloc_get_type(private_data,
979 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
980 just a bug in their server, but we better do the same */
981 if (reason == PVFS_WAIT_CANCEL) {
985 if (reason == PVFS_WAIT_TIMEOUT) {
987 !timeval_expired(final_timeout)) {
989 * we need to retry periodictly
990 * after an EAGAIN as there's
991 * no way the kernel tell us
992 * an oplock is released.
996 /* if it timed out, then give the failure
999 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
1000 req->async_states->send_fn(req);
1007 /* try the open again, which could trigger another retry setup
1008 if it wants to, so we have to unmark the async flag so we
1009 will know if it does a second async reply */
1010 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
1012 status = pvfs_open(ntvfs, req, io);
1013 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
1014 /* the 2nd try also replied async, so we don't send
1019 /* re-mark it async, just in case someone up the chain does
1020 paranoid checking */
1021 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1023 /* send the reply up the chain */
1024 req->async_states->status = status;
1025 req->async_states->send_fn(req);
1030 special handling for openx DENY_DOS semantics
1032 This function attempts a reference open using an existing handle. If its allowed,
1033 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
1034 open processing continues.
1036 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
1037 struct ntvfs_request *req, union smb_open *io,
1038 struct pvfs_file *f, struct odb_lock *lck)
1040 struct pvfs_state *pvfs = ntvfs->private_data;
1041 struct pvfs_file *f2;
1042 struct pvfs_filename *name;
1045 /* search for an existing open with the right parameters. Note
1046 the magic ntcreatex options flag, which is set in the
1047 generic mapping code. This might look ugly, but its
1048 actually pretty much now w2k does it internally as well.
1050 If you look at the BASE-DENYDOS test you will see that a
1051 DENY_DOS is a very special case, and in the right
1052 circumstances you actually get the _same_ handle back
1053 twice, rather than a new handle.
1055 for (f2=pvfs->files.list;f2;f2=f2->next) {
1057 f2->ntvfs->session_info == req->session_info &&
1058 f2->ntvfs->smbpid == req->smbpid &&
1059 (f2->handle->create_options &
1060 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
1061 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
1062 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1063 strcasecmp_m(f2->handle->name->original_name,
1064 io->generic.in.fname)==0) {
1070 return NT_STATUS_SHARING_VIOLATION;
1073 /* quite an insane set of semantics ... */
1074 if (is_exe_filename(io->generic.in.fname) &&
1075 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1076 return NT_STATUS_SHARING_VIOLATION;
1080 setup a reference to the existing handle
1082 talloc_free(f->handle);
1083 f->handle = talloc_reference(f, f2->handle);
1087 name = f->handle->name;
1089 io->generic.out.oplock_level = OPLOCK_NONE;
1090 io->generic.out.file.ntvfs = f->ntvfs;
1091 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1092 io->generic.out.create_time = name->dos.create_time;
1093 io->generic.out.access_time = name->dos.access_time;
1094 io->generic.out.write_time = name->dos.write_time;
1095 io->generic.out.change_time = name->dos.change_time;
1096 io->generic.out.attrib = name->dos.attrib;
1097 io->generic.out.alloc_size = name->dos.alloc_size;
1098 io->generic.out.size = name->st.st_size;
1099 io->generic.out.file_type = FILE_TYPE_DISK;
1100 io->generic.out.ipc_state = 0;
1101 io->generic.out.is_directory = 0;
1103 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1104 NT_STATUS_NOT_OK_RETURN(status);
1106 return NT_STATUS_OK;
1112 setup for a open retry after a sharing violation
1114 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1115 struct ntvfs_request *req,
1117 struct pvfs_file *f,
1118 struct odb_lock *lck,
1119 NTSTATUS parent_status)
1121 struct pvfs_state *pvfs = ntvfs->private_data;
1123 struct timeval end_time;
1124 struct timeval *final_timeout = NULL;
1126 if (io->generic.in.create_options &
1127 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1128 /* see if we can satisfy the request using the special DENY_DOS
1130 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1131 if (NT_STATUS_IS_OK(status)) {
1136 /* the retry should allocate a new file handle */
1139 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1140 end_time = timeval_add(&req->statistics.request_time,
1141 0, pvfs->sharing_violation_delay);
1142 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1143 end_time = timeval_add(&req->statistics.request_time,
1144 pvfs->oplock_break_timeout, 0);
1145 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1147 * we got EAGAIN which means a unix application
1148 * has an oplock or share mode
1150 * we retry every 4/5 of the sharing violation delay
1151 * to see if the unix application
1152 * has released the oplock or share mode.
1154 final_timeout = talloc(req, struct timeval);
1155 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1156 *final_timeout = timeval_add(&req->statistics.request_time,
1157 pvfs->oplock_break_timeout,
1159 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1160 end_time = timeval_min(final_timeout, &end_time);
1162 return NT_STATUS_INTERNAL_ERROR;
1165 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1166 final_timeout, pvfs_retry_open_sharing);
1172 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1173 struct ntvfs_request *req, union smb_open *io)
1175 struct pvfs_state *pvfs = ntvfs->private_data;
1177 struct pvfs_filename *name;
1178 struct pvfs_file *f;
1179 struct ntvfs_handle *h;
1182 struct odb_lock *lck;
1183 uint32_t create_options;
1184 uint32_t share_access;
1185 uint32_t access_mask;
1186 uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1188 bool stream_existed, stream_truncate=false;
1189 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1190 bool allow_level_II_oplock = false;
1192 /* use the generic mapping code to avoid implementing all the
1193 different open calls. */
1194 if (io->generic.level != RAW_OPEN_GENERIC &&
1195 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1196 return ntvfs_map_open(ntvfs, req, io);
1199 ZERO_STRUCT(io->generic.out);
1201 create_options = io->generic.in.create_options;
1202 share_access = io->generic.in.share_access;
1203 access_mask = io->generic.in.access_mask;
1205 if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1206 return NT_STATUS_INVALID_PARAMETER;
1209 if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1210 return NT_STATUS_NOT_SUPPORTED;
1213 /* TODO: When we implement HSM, add a hook here not to pull
1214 * the actual file off tape, when this option is passed from
1216 if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1220 /* These options are ignored */
1221 if (create_options & (NTCREATEX_OPTIONS_FREE_SPACE_QUERY | NTCREATEX_OPTIONS_OPFILTER)) {
1225 /* other create options are not allowed */
1226 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1227 !(access_mask & SEC_STD_DELETE)) {
1228 return NT_STATUS_INVALID_PARAMETER;
1231 if (access_mask & SEC_MASK_INVALID) {
1232 return NT_STATUS_ACCESS_DENIED;
1235 /* what does this bit really mean?? */
1236 if (req->ctx->protocol == PROTOCOL_SMB2 &&
1237 access_mask == SEC_STD_SYNCHRONIZE) {
1238 return NT_STATUS_ACCESS_DENIED;
1241 if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1242 FILE_ATTRIBUTE_VOLUME|
1243 (~FILE_ATTRIBUTE_ALL_MASK))) {
1244 return NT_STATUS_INVALID_PARAMETER;
1247 /* we ignore some file_attr bits */
1248 io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED |
1249 FILE_ATTRIBUTE_COMPRESSED |
1250 FILE_ATTRIBUTE_REPARSE_POINT |
1251 FILE_ATTRIBUTE_SPARSE |
1252 FILE_ATTRIBUTE_NORMAL);
1254 /* resolve the cifs name to a posix name */
1255 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1256 PVFS_RESOLVE_STREAMS, &name);
1257 if (!NT_STATUS_IS_OK(status)) {
1261 /* if the client specified that it must not be a directory then
1262 check that it isn't */
1263 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1264 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1265 return NT_STATUS_FILE_IS_A_DIRECTORY;
1268 /* if the client specified that it must be a directory then
1270 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1271 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1272 return NT_STATUS_NOT_A_DIRECTORY;
1275 /* directory opens are handled separately */
1276 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1277 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1278 return pvfs_open_directory(pvfs, req, name, io);
1281 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1282 open doesn't match */
1283 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1287 switch (io->generic.in.open_disposition) {
1288 case NTCREATEX_DISP_SUPERSEDE:
1289 case NTCREATEX_DISP_OVERWRITE_IF:
1290 if (name->stream_name == NULL) {
1293 stream_truncate = true;
1295 create_action = NTCREATEX_ACTION_TRUNCATED;
1298 case NTCREATEX_DISP_OPEN:
1299 if (!name->stream_exists) {
1300 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1305 case NTCREATEX_DISP_OVERWRITE:
1306 if (!name->stream_exists) {
1307 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1309 if (name->stream_name == NULL) {
1312 stream_truncate = true;
1314 create_action = NTCREATEX_ACTION_TRUNCATED;
1317 case NTCREATEX_DISP_CREATE:
1318 if (name->stream_exists) {
1319 return NT_STATUS_OBJECT_NAME_COLLISION;
1324 case NTCREATEX_DISP_OPEN_IF:
1329 return NT_STATUS_INVALID_PARAMETER;
1332 /* handle creating a new file separately */
1333 if (!name->exists) {
1334 status = pvfs_create_file(pvfs, req, name, io);
1335 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1339 /* we've hit a race - the file was created during this call */
1340 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1344 /* try re-resolving the name */
1345 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1346 if (!NT_STATUS_IS_OK(status)) {
1349 /* fall through to a normal open */
1352 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1353 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1354 return NT_STATUS_CANNOT_DELETE;
1357 /* check the security descriptor */
1358 status = pvfs_access_check(pvfs, req, name, &access_mask);
1359 NT_STATUS_NOT_OK_RETURN(status);
1361 if (io->generic.in.query_maximal_access) {
1362 status = pvfs_access_maximal_allowed(pvfs, req, name,
1363 &io->generic.out.maximal_access);
1364 NT_STATUS_NOT_OK_RETURN(status);
1367 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1368 NT_STATUS_NOT_OK_RETURN(status);
1370 f = talloc(h, struct pvfs_file);
1372 return NT_STATUS_NO_MEMORY;
1375 f->handle = talloc(f, struct pvfs_file_handle);
1376 if (f->handle == NULL) {
1377 return NT_STATUS_NO_MEMORY;
1382 f->pending_list = NULL;
1384 f->share_access = io->generic.in.share_access;
1385 f->access_mask = access_mask;
1386 f->impersonation = io->generic.in.impersonation;
1387 f->notify_buffer = NULL;
1390 f->handle->pvfs = pvfs;
1392 f->handle->name = talloc_steal(f->handle, name);
1393 f->handle->create_options = io->generic.in.create_options;
1394 f->handle->seek_offset = 0;
1395 f->handle->position = 0;
1396 f->handle->mode = 0;
1397 f->handle->oplock = NULL;
1398 f->handle->have_opendb_entry = false;
1399 ZERO_STRUCT(f->handle->write_time);
1400 f->handle->open_completed = false;
1402 /* form the lock context used for byte range locking and
1404 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1405 if (!NT_STATUS_IS_OK(status)) {
1409 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1410 if (!NT_STATUS_IS_OK(status)) {
1414 /* get a lock on this file before the actual open */
1415 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1417 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1419 /* we were supposed to do a blocking lock, so something
1421 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1424 DLIST_ADD(pvfs->files.list, f);
1426 /* setup a destructor to avoid file descriptor leaks on
1427 abnormal termination */
1428 talloc_set_destructor(f, pvfs_fnum_destructor);
1429 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1432 * Only SMB2 takes care of the delete_on_close,
1435 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1436 req->ctx->protocol == PROTOCOL_SMB2) {
1437 del_on_close = true;
1439 del_on_close = false;
1442 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1443 oplock_level = OPLOCK_NONE;
1444 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1445 oplock_level = OPLOCK_BATCH;
1446 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1447 oplock_level = OPLOCK_EXCLUSIVE;
1450 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1451 allow_level_II_oplock = true;
1454 /* see if we are allowed to open at the same time as existing opens */
1455 status = odb_can_open(lck, name->stream_id,
1456 share_access, access_mask, del_on_close,
1457 io->generic.in.open_disposition, false);
1460 * on a sharing violation we need to retry when the file is closed by
1461 * the other user, or after 1 second
1462 * on a non granted oplock we need to retry when the file is closed by
1463 * the other user, or after 30 seconds
1465 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1466 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1467 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1468 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1471 if (!NT_STATUS_IS_OK(status)) {
1476 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1482 /* do the actual open */
1483 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1485 status = pvfs_map_errno(f->pvfs, errno);
1488 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1490 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1491 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1492 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1501 /* now really mark the file as open */
1502 status = odb_open_file(lck, f->handle, name->full_name,
1503 &f->handle->fd, name->dos.write_time,
1504 allow_level_II_oplock,
1505 oplock_level, &oplock_granted);
1507 if (!NT_STATUS_IS_OK(status)) {
1512 f->handle->have_opendb_entry = true;
1514 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1515 oplock_granted = OPLOCK_BATCH;
1516 } else if (oplock_granted != OPLOCK_NONE) {
1517 status = pvfs_setup_oplock(f, oplock_granted);
1518 if (!NT_STATUS_IS_OK(status)) {
1524 stream_existed = name->stream_exists;
1526 /* if this was a stream create then create the stream as well */
1527 if (!name->stream_exists) {
1528 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1529 if (!NT_STATUS_IS_OK(status)) {
1533 if (stream_truncate) {
1534 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1535 if (!NT_STATUS_IS_OK(status)) {
1542 /* re-resolve the open fd */
1543 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1544 if (!NT_STATUS_IS_OK(status)) {
1549 if (f->handle->name->stream_id == 0 &&
1550 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1551 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1552 /* for overwrite we need to replace file permissions */
1553 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1554 mode_t mode = pvfs_fileperms(pvfs, attrib);
1555 if (fchmod(fd, mode) == -1) {
1557 return pvfs_map_errno(pvfs, errno);
1559 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1560 name->dos.attrib = attrib;
1561 status = pvfs_dosattrib_save(pvfs, name, fd);
1562 if (!NT_STATUS_IS_OK(status)) {
1570 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1571 NT_STATUS_NOT_OK_RETURN(status);
1573 /* mark the open as having completed fully, so delete on close
1575 f->handle->open_completed = true;
1577 io->generic.out.oplock_level = oplock_granted;
1578 io->generic.out.file.ntvfs = h;
1579 io->generic.out.create_action = stream_existed?
1580 create_action:NTCREATEX_ACTION_CREATED;
1582 io->generic.out.create_time = name->dos.create_time;
1583 io->generic.out.access_time = name->dos.access_time;
1584 io->generic.out.write_time = name->dos.write_time;
1585 io->generic.out.change_time = name->dos.change_time;
1586 io->generic.out.attrib = name->dos.attrib;
1587 io->generic.out.alloc_size = name->dos.alloc_size;
1588 io->generic.out.size = name->st.st_size;
1589 io->generic.out.file_type = FILE_TYPE_DISK;
1590 io->generic.out.ipc_state = 0;
1591 io->generic.out.is_directory = 0;
1593 return NT_STATUS_OK;
1600 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1601 struct ntvfs_request *req, union smb_close *io)
1603 struct pvfs_state *pvfs = ntvfs->private_data;
1604 struct pvfs_file *f;
1606 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1607 return NT_STATUS_DOS(ERRSRV, ERRerror);
1610 if (io->generic.level != RAW_CLOSE_GENERIC) {
1611 return ntvfs_map_close(ntvfs, req, io);
1614 f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1616 return NT_STATUS_INVALID_HANDLE;
1619 if (!null_time(io->generic.in.write_time)) {
1620 f->handle->write_time.update_forced = false;
1621 f->handle->write_time.update_on_close = true;
1622 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1625 if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1626 struct pvfs_filename *name;
1628 struct pvfs_file_handle *h = f->handle;
1630 status = pvfs_resolve_name_handle(pvfs, h);
1631 if (!NT_STATUS_IS_OK(status)) {
1636 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1637 io->generic.out.create_time = name->dos.create_time;
1638 io->generic.out.access_time = name->dos.access_time;
1639 io->generic.out.write_time = name->dos.write_time;
1640 io->generic.out.change_time = name->dos.change_time;
1641 io->generic.out.alloc_size = name->dos.alloc_size;
1642 io->generic.out.size = name->st.st_size;
1643 io->generic.out.file_attr = name->dos.attrib;
1645 ZERO_STRUCT(io->generic.out);
1650 return NT_STATUS_OK;
1655 logoff - close all file descriptors open by a vuid
1657 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1658 struct ntvfs_request *req)
1660 struct pvfs_state *pvfs = ntvfs->private_data;
1661 struct pvfs_file *f, *next;
1663 for (f=pvfs->files.list;f;f=next) {
1665 if (f->ntvfs->session_info == req->session_info) {
1670 return NT_STATUS_OK;
1675 exit - close files for the current pid
1677 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1678 struct ntvfs_request *req)
1680 struct pvfs_state *pvfs = ntvfs->private_data;
1681 struct pvfs_file *f, *next;
1683 for (f=pvfs->files.list;f;f=next) {
1685 if (f->ntvfs->session_info == req->session_info &&
1686 f->ntvfs->smbpid == req->smbpid) {
1691 return NT_STATUS_OK;
1696 change the delete on close flag on an already open file
1698 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1699 struct ntvfs_request *req,
1700 struct pvfs_file *f, bool del_on_close)
1702 struct odb_lock *lck;
1705 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1706 return NT_STATUS_CANNOT_DELETE;
1709 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1710 !pvfs_directory_empty(pvfs, f->handle->name)) {
1711 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1715 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1717 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1720 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1722 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1725 status = odb_set_delete_on_close(lck, del_on_close);
1734 determine if a file can be deleted, or if it is prevented by an
1737 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1738 struct ntvfs_request *req,
1739 struct pvfs_filename *name,
1740 struct odb_lock **lckp)
1744 struct odb_lock *lck;
1745 uint32_t share_access;
1746 uint32_t access_mask;
1747 bool delete_on_close;
1749 status = pvfs_locking_key(name, name, &key);
1750 if (!NT_STATUS_IS_OK(status)) {
1751 return NT_STATUS_NO_MEMORY;
1754 lck = odb_lock(req, pvfs->odb_context, &key);
1756 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1757 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1760 share_access = NTCREATEX_SHARE_ACCESS_READ |
1761 NTCREATEX_SHARE_ACCESS_WRITE |
1762 NTCREATEX_SHARE_ACCESS_DELETE;
1763 access_mask = SEC_STD_DELETE;
1764 delete_on_close = true;
1766 status = odb_can_open(lck, name->stream_id,
1767 share_access, access_mask, delete_on_close,
1768 NTCREATEX_DISP_OPEN, false);
1770 if (NT_STATUS_IS_OK(status)) {
1771 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1775 * if it's a sharing violation or we got no oplock
1776 * only keep the lock if the caller requested access
1779 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1780 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1786 } else if (!NT_STATUS_IS_OK(status)) {
1799 determine if a file can be renamed, or if it is prevented by an
1802 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1803 struct ntvfs_request *req,
1804 struct pvfs_filename *name,
1805 struct odb_lock **lckp)
1809 struct odb_lock *lck;
1810 uint32_t share_access;
1811 uint32_t access_mask;
1812 bool delete_on_close;
1814 status = pvfs_locking_key(name, name, &key);
1815 if (!NT_STATUS_IS_OK(status)) {
1816 return NT_STATUS_NO_MEMORY;
1819 lck = odb_lock(req, pvfs->odb_context, &key);
1821 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1822 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1825 share_access = NTCREATEX_SHARE_ACCESS_READ |
1826 NTCREATEX_SHARE_ACCESS_WRITE;
1827 access_mask = SEC_STD_DELETE;
1828 delete_on_close = false;
1830 status = odb_can_open(lck, name->stream_id,
1831 share_access, access_mask, delete_on_close,
1832 NTCREATEX_DISP_OPEN, false);
1835 * if it's a sharing violation or we got no oplock
1836 * only keep the lock if the caller requested access
1839 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1840 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1846 } else if (!NT_STATUS_IS_OK(status)) {
1859 determine if the file size of a file can be changed,
1860 or if it is prevented by an already open file
1862 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1863 struct ntvfs_request *req,
1864 struct pvfs_filename *name,
1865 struct odb_lock **lckp)
1869 struct odb_lock *lck;
1870 uint32_t share_access;
1871 uint32_t access_mask;
1873 bool delete_on_close;
1875 status = pvfs_locking_key(name, name, &key);
1876 if (!NT_STATUS_IS_OK(status)) {
1877 return NT_STATUS_NO_MEMORY;
1880 lck = odb_lock(req, pvfs->odb_context, &key);
1882 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1883 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1886 share_access = NTCREATEX_SHARE_ACCESS_READ |
1887 NTCREATEX_SHARE_ACCESS_WRITE |
1888 NTCREATEX_SHARE_ACCESS_DELETE;
1890 * I would have thought that we would need to pass
1891 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1893 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1894 * to set the filesize.
1898 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1899 delete_on_close = false;
1900 break_to_none = true;
1902 status = odb_can_open(lck, name->stream_id,
1903 share_access, access_mask, delete_on_close,
1904 NTCREATEX_DISP_OPEN, break_to_none);
1907 * if it's a sharing violation or we got no oplock
1908 * only keep the lock if the caller requested access
1911 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1912 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1918 } else if (!NT_STATUS_IS_OK(status)) {
1931 determine if file meta data can be accessed, or if it is prevented by an
1934 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1935 struct ntvfs_request *req,
1936 struct pvfs_filename *name)
1940 struct odb_lock *lck;
1941 uint32_t share_access;
1942 uint32_t access_mask;
1943 bool delete_on_close;
1945 status = pvfs_locking_key(name, name, &key);
1946 if (!NT_STATUS_IS_OK(status)) {
1947 return NT_STATUS_NO_MEMORY;
1950 lck = odb_lock(req, pvfs->odb_context, &key);
1952 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1953 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1956 share_access = NTCREATEX_SHARE_ACCESS_READ |
1957 NTCREATEX_SHARE_ACCESS_WRITE;
1958 access_mask = SEC_FILE_READ_ATTRIBUTE;
1959 delete_on_close = false;
1961 status = odb_can_open(lck, name->stream_id,
1962 share_access, access_mask, delete_on_close,
1963 NTCREATEX_DISP_OPEN, false);
1965 if (!NT_STATUS_IS_OK(status)) {
1974 determine if delete on close is set on
1976 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1981 status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key,
1982 &del_on_close, NULL);
1983 if (!NT_STATUS_IS_OK(status)) {
1984 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1988 return del_on_close;