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 /* check that the parent isn't opened with delete on close set */
635 status = pvfs_resolve_parent(pvfs, req, name, &parent);
636 if (NT_STATUS_IS_OK(status)) {
637 DATA_BLOB locking_key;
638 status = pvfs_locking_key(parent, req, &locking_key);
639 NT_STATUS_NOT_OK_RETURN(status);
640 status = odb_get_file_infos(pvfs->odb_context, &locking_key,
641 &del_on_close, NULL);
642 NT_STATUS_NOT_OK_RETURN(status);
644 return NT_STATUS_DELETE_PENDING;
648 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
654 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
655 NT_STATUS_NOT_OK_RETURN(status);
657 f = talloc(h, struct pvfs_file);
658 NT_STATUS_HAVE_NO_MEMORY(f);
660 f->handle = talloc(f, struct pvfs_file_handle);
661 NT_STATUS_HAVE_NO_MEMORY(f->handle);
663 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
664 mode = pvfs_fileperms(pvfs, attrib);
666 /* create the file */
667 fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
669 return pvfs_map_errno(pvfs, errno);
672 pvfs_xattr_unlink_hook(pvfs, name->full_name);
674 /* if this was a stream create then create the stream as well */
675 if (name->stream_name) {
676 status = pvfs_stream_create(pvfs, name, fd);
677 if (!NT_STATUS_IS_OK(status)) {
683 /* re-resolve the open fd */
684 status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
685 if (!NT_STATUS_IS_OK(status)) {
690 /* support initial alloc sizes */
691 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
692 name->dos.attrib = attrib;
693 status = pvfs_dosattrib_save(pvfs, name, fd);
694 if (!NT_STATUS_IS_OK(status)) {
699 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
700 if (!NT_STATUS_IS_OK(status)) {
704 if (io->generic.in.query_maximal_access) {
705 status = pvfs_access_maximal_allowed(pvfs, req, name,
706 &io->generic.out.maximal_access);
707 NT_STATUS_NOT_OK_RETURN(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 create_options_must_ignore_mask;
1185 uint32_t share_access;
1186 uint32_t access_mask;
1187 uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1189 bool stream_existed, stream_truncate=false;
1190 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1191 bool allow_level_II_oplock = false;
1193 /* use the generic mapping code to avoid implementing all the
1194 different open calls. */
1195 if (io->generic.level != RAW_OPEN_GENERIC &&
1196 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1197 return ntvfs_map_open(ntvfs, req, io);
1200 ZERO_STRUCT(io->generic.out);
1202 create_options = io->generic.in.create_options;
1203 share_access = io->generic.in.share_access;
1204 access_mask = io->generic.in.access_mask;
1206 if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1207 return NT_STATUS_INVALID_PARAMETER;
1211 * These options are ignored,
1212 * but we reuse some of them as private values for the generic mapping
1214 create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
1215 create_options_must_ignore_mask &= ~NTCREATEX_OPTIONS_PRIVATE_MASK;
1216 create_options &= ~create_options_must_ignore_mask;
1218 if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1219 DEBUG(2,(__location__ " create_options 0x%x not supported\n",
1221 return NT_STATUS_NOT_SUPPORTED;
1224 if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
1225 return NT_STATUS_INVALID_PARAMETER;
1228 /* TODO: When we implement HSM, add a hook here not to pull
1229 * the actual file off tape, when this option is passed from
1231 if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1235 /* TODO: If (unlikely) Linux does a good compressed
1236 * filesystem, we might need an ioctl call for this */
1237 if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
1241 if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
1242 create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
1245 /* Open the file with sync, if they asked for it, but
1246 'strict sync = no' turns this client request into a no-op */
1247 if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && !(pvfs->flags | PVFS_FLAG_STRICT_SYNC)) {
1252 /* other create options are not allowed */
1253 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1254 !(access_mask & SEC_STD_DELETE)) {
1255 return NT_STATUS_INVALID_PARAMETER;
1258 if (access_mask & SEC_MASK_INVALID) {
1259 return NT_STATUS_ACCESS_DENIED;
1262 /* what does this bit really mean?? */
1263 if (req->ctx->protocol == PROTOCOL_SMB2 &&
1264 access_mask == SEC_STD_SYNCHRONIZE) {
1265 return NT_STATUS_ACCESS_DENIED;
1268 if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1269 FILE_ATTRIBUTE_VOLUME|
1270 (~FILE_ATTRIBUTE_ALL_MASK))) {
1271 return NT_STATUS_INVALID_PARAMETER;
1274 /* we ignore some file_attr bits */
1275 io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED |
1276 FILE_ATTRIBUTE_COMPRESSED |
1277 FILE_ATTRIBUTE_REPARSE_POINT |
1278 FILE_ATTRIBUTE_SPARSE |
1279 FILE_ATTRIBUTE_NORMAL);
1281 /* resolve the cifs name to a posix name */
1282 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1283 PVFS_RESOLVE_STREAMS, &name);
1284 if (!NT_STATUS_IS_OK(status)) {
1288 /* if the client specified that it must not be a directory then
1289 check that it isn't */
1290 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1291 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1292 return NT_STATUS_FILE_IS_A_DIRECTORY;
1295 /* if the client specified that it must be a directory then
1297 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1298 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1299 return NT_STATUS_NOT_A_DIRECTORY;
1302 /* directory opens are handled separately */
1303 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1304 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1305 return pvfs_open_directory(pvfs, req, name, io);
1308 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1309 open doesn't match */
1310 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1312 switch (io->generic.in.open_disposition) {
1313 case NTCREATEX_DISP_SUPERSEDE:
1314 case NTCREATEX_DISP_OVERWRITE_IF:
1315 if (name->stream_name == NULL) {
1318 stream_truncate = true;
1320 create_action = NTCREATEX_ACTION_TRUNCATED;
1323 case NTCREATEX_DISP_OPEN:
1324 if (!name->stream_exists) {
1325 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1330 case NTCREATEX_DISP_OVERWRITE:
1331 if (!name->stream_exists) {
1332 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1334 if (name->stream_name == NULL) {
1337 stream_truncate = true;
1339 create_action = NTCREATEX_ACTION_TRUNCATED;
1342 case NTCREATEX_DISP_CREATE:
1343 if (name->stream_exists) {
1344 return NT_STATUS_OBJECT_NAME_COLLISION;
1349 case NTCREATEX_DISP_OPEN_IF:
1354 return NT_STATUS_INVALID_PARAMETER;
1357 /* handle creating a new file separately */
1358 if (!name->exists) {
1359 status = pvfs_create_file(pvfs, req, name, io);
1360 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1364 /* we've hit a race - the file was created during this call */
1365 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1369 /* try re-resolving the name */
1370 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1371 if (!NT_STATUS_IS_OK(status)) {
1374 /* fall through to a normal open */
1377 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1378 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1379 return NT_STATUS_CANNOT_DELETE;
1382 /* check the security descriptor */
1383 status = pvfs_access_check(pvfs, req, name, &access_mask);
1384 NT_STATUS_NOT_OK_RETURN(status);
1386 if (io->generic.in.query_maximal_access) {
1387 status = pvfs_access_maximal_allowed(pvfs, req, name,
1388 &io->generic.out.maximal_access);
1389 NT_STATUS_NOT_OK_RETURN(status);
1392 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1393 NT_STATUS_NOT_OK_RETURN(status);
1395 f = talloc(h, struct pvfs_file);
1397 return NT_STATUS_NO_MEMORY;
1400 f->handle = talloc(f, struct pvfs_file_handle);
1401 if (f->handle == NULL) {
1402 return NT_STATUS_NO_MEMORY;
1407 f->pending_list = NULL;
1409 f->share_access = io->generic.in.share_access;
1410 f->access_mask = access_mask;
1411 f->impersonation = io->generic.in.impersonation;
1412 f->notify_buffer = NULL;
1415 f->handle->pvfs = pvfs;
1417 f->handle->name = talloc_steal(f->handle, name);
1418 f->handle->create_options = io->generic.in.create_options;
1419 f->handle->seek_offset = 0;
1420 f->handle->position = 0;
1421 f->handle->mode = 0;
1422 f->handle->oplock = NULL;
1423 f->handle->have_opendb_entry = false;
1424 ZERO_STRUCT(f->handle->write_time);
1425 f->handle->open_completed = false;
1427 /* form the lock context used for byte range locking and
1429 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1430 if (!NT_STATUS_IS_OK(status)) {
1434 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1435 if (!NT_STATUS_IS_OK(status)) {
1439 /* get a lock on this file before the actual open */
1440 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1442 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1444 /* we were supposed to do a blocking lock, so something
1446 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1449 DLIST_ADD(pvfs->files.list, f);
1451 /* setup a destructor to avoid file descriptor leaks on
1452 abnormal termination */
1453 talloc_set_destructor(f, pvfs_fnum_destructor);
1454 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1457 * Only SMB2 takes care of the delete_on_close,
1460 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1461 req->ctx->protocol == PROTOCOL_SMB2) {
1462 del_on_close = true;
1464 del_on_close = false;
1467 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1468 oplock_level = OPLOCK_NONE;
1469 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1470 oplock_level = OPLOCK_BATCH;
1471 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1472 oplock_level = OPLOCK_EXCLUSIVE;
1475 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1476 allow_level_II_oplock = true;
1479 /* see if we are allowed to open at the same time as existing opens */
1480 status = odb_can_open(lck, name->stream_id,
1481 share_access, access_mask, del_on_close,
1482 io->generic.in.open_disposition, false);
1485 * on a sharing violation we need to retry when the file is closed by
1486 * the other user, or after 1 second
1487 * on a non granted oplock we need to retry when the file is closed by
1488 * the other user, or after 30 seconds
1490 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1491 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1492 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1493 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1496 if (!NT_STATUS_IS_OK(status)) {
1501 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1507 /* do the actual open */
1508 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1510 status = pvfs_map_errno(f->pvfs, errno);
1513 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1515 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1516 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1517 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1526 /* now really mark the file as open */
1527 status = odb_open_file(lck, f->handle, name->full_name,
1528 &f->handle->fd, name->dos.write_time,
1529 allow_level_II_oplock,
1530 oplock_level, &oplock_granted);
1532 if (!NT_STATUS_IS_OK(status)) {
1537 f->handle->have_opendb_entry = true;
1539 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1540 oplock_granted = OPLOCK_BATCH;
1541 } else if (oplock_granted != OPLOCK_NONE) {
1542 status = pvfs_setup_oplock(f, oplock_granted);
1543 if (!NT_STATUS_IS_OK(status)) {
1549 stream_existed = name->stream_exists;
1551 /* if this was a stream create then create the stream as well */
1552 if (!name->stream_exists) {
1553 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1554 if (!NT_STATUS_IS_OK(status)) {
1558 if (stream_truncate) {
1559 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1560 if (!NT_STATUS_IS_OK(status)) {
1567 /* re-resolve the open fd */
1568 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1569 if (!NT_STATUS_IS_OK(status)) {
1574 if (f->handle->name->stream_id == 0 &&
1575 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1576 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1577 /* for overwrite we need to replace file permissions */
1578 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1579 mode_t mode = pvfs_fileperms(pvfs, attrib);
1580 if (fchmod(fd, mode) == -1) {
1582 return pvfs_map_errno(pvfs, errno);
1584 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1585 name->dos.attrib = attrib;
1586 status = pvfs_dosattrib_save(pvfs, name, fd);
1587 if (!NT_STATUS_IS_OK(status)) {
1595 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1596 NT_STATUS_NOT_OK_RETURN(status);
1598 /* mark the open as having completed fully, so delete on close
1600 f->handle->open_completed = true;
1602 io->generic.out.oplock_level = oplock_granted;
1603 io->generic.out.file.ntvfs = h;
1604 io->generic.out.create_action = stream_existed?
1605 create_action:NTCREATEX_ACTION_CREATED;
1607 io->generic.out.create_time = name->dos.create_time;
1608 io->generic.out.access_time = name->dos.access_time;
1609 io->generic.out.write_time = name->dos.write_time;
1610 io->generic.out.change_time = name->dos.change_time;
1611 io->generic.out.attrib = name->dos.attrib;
1612 io->generic.out.alloc_size = name->dos.alloc_size;
1613 io->generic.out.size = name->st.st_size;
1614 io->generic.out.file_type = FILE_TYPE_DISK;
1615 io->generic.out.ipc_state = 0;
1616 io->generic.out.is_directory = 0;
1618 return NT_STATUS_OK;
1625 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1626 struct ntvfs_request *req, union smb_close *io)
1628 struct pvfs_state *pvfs = ntvfs->private_data;
1629 struct pvfs_file *f;
1631 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1632 return NT_STATUS_DOS(ERRSRV, ERRerror);
1635 if (io->generic.level != RAW_CLOSE_GENERIC) {
1636 return ntvfs_map_close(ntvfs, req, io);
1639 f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1641 return NT_STATUS_INVALID_HANDLE;
1644 if (!null_time(io->generic.in.write_time)) {
1645 f->handle->write_time.update_forced = false;
1646 f->handle->write_time.update_on_close = true;
1647 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1650 if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1651 struct pvfs_filename *name;
1653 struct pvfs_file_handle *h = f->handle;
1655 status = pvfs_resolve_name_handle(pvfs, h);
1656 if (!NT_STATUS_IS_OK(status)) {
1661 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1662 io->generic.out.create_time = name->dos.create_time;
1663 io->generic.out.access_time = name->dos.access_time;
1664 io->generic.out.write_time = name->dos.write_time;
1665 io->generic.out.change_time = name->dos.change_time;
1666 io->generic.out.alloc_size = name->dos.alloc_size;
1667 io->generic.out.size = name->st.st_size;
1668 io->generic.out.file_attr = name->dos.attrib;
1670 ZERO_STRUCT(io->generic.out);
1675 return NT_STATUS_OK;
1680 logoff - close all file descriptors open by a vuid
1682 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1683 struct ntvfs_request *req)
1685 struct pvfs_state *pvfs = ntvfs->private_data;
1686 struct pvfs_file *f, *next;
1688 for (f=pvfs->files.list;f;f=next) {
1690 if (f->ntvfs->session_info == req->session_info) {
1695 return NT_STATUS_OK;
1700 exit - close files for the current pid
1702 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1703 struct ntvfs_request *req)
1705 struct pvfs_state *pvfs = ntvfs->private_data;
1706 struct pvfs_file *f, *next;
1708 for (f=pvfs->files.list;f;f=next) {
1710 if (f->ntvfs->session_info == req->session_info &&
1711 f->ntvfs->smbpid == req->smbpid) {
1716 return NT_STATUS_OK;
1721 change the delete on close flag on an already open file
1723 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1724 struct ntvfs_request *req,
1725 struct pvfs_file *f, bool del_on_close)
1727 struct odb_lock *lck;
1730 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1731 return NT_STATUS_CANNOT_DELETE;
1734 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1735 !pvfs_directory_empty(pvfs, f->handle->name)) {
1736 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1740 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1742 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1745 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1747 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1750 status = odb_set_delete_on_close(lck, del_on_close);
1759 determine if a file can be deleted, or if it is prevented by an
1762 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1763 struct ntvfs_request *req,
1764 struct pvfs_filename *name,
1765 struct odb_lock **lckp)
1769 struct odb_lock *lck;
1770 uint32_t share_access;
1771 uint32_t access_mask;
1772 bool delete_on_close;
1774 status = pvfs_locking_key(name, name, &key);
1775 if (!NT_STATUS_IS_OK(status)) {
1776 return NT_STATUS_NO_MEMORY;
1779 lck = odb_lock(req, pvfs->odb_context, &key);
1781 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1782 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1785 share_access = NTCREATEX_SHARE_ACCESS_READ |
1786 NTCREATEX_SHARE_ACCESS_WRITE |
1787 NTCREATEX_SHARE_ACCESS_DELETE;
1788 access_mask = SEC_STD_DELETE;
1789 delete_on_close = true;
1791 status = odb_can_open(lck, name->stream_id,
1792 share_access, access_mask, delete_on_close,
1793 NTCREATEX_DISP_OPEN, false);
1795 if (NT_STATUS_IS_OK(status)) {
1796 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1800 * if it's a sharing violation or we got no oplock
1801 * only keep the lock if the caller requested access
1804 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1805 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1811 } else if (!NT_STATUS_IS_OK(status)) {
1824 determine if a file can be renamed, or if it is prevented by an
1827 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1828 struct ntvfs_request *req,
1829 struct pvfs_filename *name,
1830 struct odb_lock **lckp)
1834 struct odb_lock *lck;
1835 uint32_t share_access;
1836 uint32_t access_mask;
1837 bool delete_on_close;
1839 status = pvfs_locking_key(name, name, &key);
1840 if (!NT_STATUS_IS_OK(status)) {
1841 return NT_STATUS_NO_MEMORY;
1844 lck = odb_lock(req, pvfs->odb_context, &key);
1846 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1847 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1850 share_access = NTCREATEX_SHARE_ACCESS_READ |
1851 NTCREATEX_SHARE_ACCESS_WRITE;
1852 access_mask = SEC_STD_DELETE;
1853 delete_on_close = false;
1855 status = odb_can_open(lck, name->stream_id,
1856 share_access, access_mask, delete_on_close,
1857 NTCREATEX_DISP_OPEN, false);
1860 * if it's a sharing violation or we got no oplock
1861 * only keep the lock if the caller requested access
1864 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1865 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1871 } else if (!NT_STATUS_IS_OK(status)) {
1884 determine if the file size of a file can be changed,
1885 or if it is prevented by an already open file
1887 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1888 struct ntvfs_request *req,
1889 struct pvfs_filename *name,
1890 struct odb_lock **lckp)
1894 struct odb_lock *lck;
1895 uint32_t share_access;
1896 uint32_t access_mask;
1898 bool delete_on_close;
1900 status = pvfs_locking_key(name, name, &key);
1901 if (!NT_STATUS_IS_OK(status)) {
1902 return NT_STATUS_NO_MEMORY;
1905 lck = odb_lock(req, pvfs->odb_context, &key);
1907 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1908 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1911 share_access = NTCREATEX_SHARE_ACCESS_READ |
1912 NTCREATEX_SHARE_ACCESS_WRITE |
1913 NTCREATEX_SHARE_ACCESS_DELETE;
1915 * I would have thought that we would need to pass
1916 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1918 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1919 * to set the filesize.
1923 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1924 delete_on_close = false;
1925 break_to_none = true;
1927 status = odb_can_open(lck, name->stream_id,
1928 share_access, access_mask, delete_on_close,
1929 NTCREATEX_DISP_OPEN, break_to_none);
1932 * if it's a sharing violation or we got no oplock
1933 * only keep the lock if the caller requested access
1936 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1937 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1943 } else if (!NT_STATUS_IS_OK(status)) {
1956 determine if file meta data can be accessed, or if it is prevented by an
1959 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1960 struct ntvfs_request *req,
1961 struct pvfs_filename *name)
1965 struct odb_lock *lck;
1966 uint32_t share_access;
1967 uint32_t access_mask;
1968 bool delete_on_close;
1970 status = pvfs_locking_key(name, name, &key);
1971 if (!NT_STATUS_IS_OK(status)) {
1972 return NT_STATUS_NO_MEMORY;
1975 lck = odb_lock(req, pvfs->odb_context, &key);
1977 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1978 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1981 share_access = NTCREATEX_SHARE_ACCESS_READ |
1982 NTCREATEX_SHARE_ACCESS_WRITE;
1983 access_mask = SEC_FILE_READ_ATTRIBUTE;
1984 delete_on_close = false;
1986 status = odb_can_open(lck, name->stream_id,
1987 share_access, access_mask, delete_on_close,
1988 NTCREATEX_DISP_OPEN, false);
1990 if (!NT_STATUS_IS_OK(status)) {
1999 determine if delete on close is set on
2001 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
2006 status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key,
2007 &del_on_close, NULL);
2008 if (!NT_STATUS_IS_OK(status)) {
2009 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2013 return del_on_close;