s3-lsa: Fix static list of luids in our privileges implementation.
[Samba/ekacnet.git] / source4 / ntvfs / posix / pvfs_open.c
blobda32c7f9b631672ebabc0804c4bc5a6b85688721
1 /*
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/>.
22 #include "includes.h"
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)
36 void *p;
37 struct pvfs_file *f;
39 p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs);
40 if (!p) return NULL;
42 f = talloc_get_type(p, struct pvfs_file);
43 if (!f) return NULL;
45 return f;
49 cleanup a open directory handle
51 static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h)
53 if (h->have_opendb_entry) {
54 struct odb_lock *lck;
55 NTSTATUS status;
56 const char *delete_path = NULL;
58 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
59 if (lck == NULL) {
60 DEBUG(0,("Unable to lock opendb for close\n"));
61 return 0;
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 (pvfs_sys_rmdir(h->pvfs, delete_path) != 0) {
77 DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
78 delete_path, strerror(errno)));
82 talloc_free(lck);
85 return 0;
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);
96 return 0;
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,
106 union smb_open *io,
107 struct security_descriptor *sd)
109 NTSTATUS status = NT_STATUS_OK;
111 /* setup any EAs that were asked for */
112 if (io->ntcreatex.in.ea_list) {
113 status = pvfs_setfileinfo_ea_set(pvfs, name, fd,
114 io->ntcreatex.in.ea_list->num_eas,
115 io->ntcreatex.in.ea_list->eas);
116 if (!NT_STATUS_IS_OK(status)) {
117 return status;
121 /* setup an initial sec_desc if requested */
122 if (sd && (sd->type & SEC_DESC_DACL_PRESENT)) {
123 union smb_setfileinfo set;
125 * TODO: set the full ACL!
126 * - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
127 * when a SACL is present on the sd,
128 * but the user doesn't have SeSecurityPrivilege
129 * - w2k3 allows it
131 set.set_secdesc.in.file.ntvfs = f->ntvfs;
132 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
133 set.set_secdesc.in.sd = sd;
135 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
138 return status;
142 form the lock context used for opendb locking. Note that we must
143 zero here to take account of possible padding on some architectures
145 NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
146 TALLOC_CTX *mem_ctx, DATA_BLOB *key)
148 struct {
149 dev_t device;
150 ino_t inode;
151 } lock_context;
152 ZERO_STRUCT(lock_context);
154 lock_context.device = name->st.st_dev;
155 lock_context.inode = name->st.st_ino;
157 *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
158 if (key->data == NULL) {
159 return NT_STATUS_NO_MEMORY;
162 return NT_STATUS_OK;
167 open a directory
169 static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
170 struct ntvfs_request *req,
171 struct pvfs_filename *name,
172 union smb_open *io)
174 struct pvfs_file *f;
175 struct ntvfs_handle *h;
176 NTSTATUS status;
177 uint32_t create_action;
178 uint32_t access_mask = io->generic.in.access_mask;
179 struct odb_lock *lck;
180 bool del_on_close;
181 uint32_t create_options;
182 uint32_t share_access;
183 bool forced;
184 struct security_descriptor *sd = NULL;
186 create_options = io->generic.in.create_options;
187 share_access = io->generic.in.share_access;
189 forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false;
191 if (name->stream_name) {
192 if (forced) {
193 return NT_STATUS_NOT_A_DIRECTORY;
194 } else {
195 return NT_STATUS_FILE_IS_A_DIRECTORY;
199 /* if the client says it must be a directory, and it isn't,
200 then fail */
201 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
202 return NT_STATUS_NOT_A_DIRECTORY;
205 /* found with gentest */
206 if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
207 (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
208 (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
209 DEBUG(3,(__location__ ": Invalid access_mask/create_options 0x%08x 0x%08x for %s\n",
210 io->ntcreatex.in.access_mask, io->ntcreatex.in.create_options, name->original_name));
211 return NT_STATUS_INVALID_PARAMETER;
214 switch (io->generic.in.open_disposition) {
215 case NTCREATEX_DISP_OPEN_IF:
216 break;
218 case NTCREATEX_DISP_OPEN:
219 if (!name->exists) {
220 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
222 break;
224 case NTCREATEX_DISP_CREATE:
225 if (name->exists) {
226 return NT_STATUS_OBJECT_NAME_COLLISION;
228 break;
230 case NTCREATEX_DISP_OVERWRITE_IF:
231 case NTCREATEX_DISP_OVERWRITE:
232 case NTCREATEX_DISP_SUPERSEDE:
233 default:
234 DEBUG(3,(__location__ ": Invalid open disposition 0x%08x for %s\n",
235 io->generic.in.open_disposition, name->original_name));
236 return NT_STATUS_INVALID_PARAMETER;
239 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
240 NT_STATUS_NOT_OK_RETURN(status);
242 f = talloc(h, struct pvfs_file);
243 if (f == NULL) {
244 return NT_STATUS_NO_MEMORY;
247 f->handle = talloc(f, struct pvfs_file_handle);
248 if (f->handle == NULL) {
249 return NT_STATUS_NO_MEMORY;
252 if (name->exists) {
253 /* check the security descriptor */
254 status = pvfs_access_check(pvfs, req, name, &access_mask);
255 } else {
256 sd = io->ntcreatex.in.sec_desc;
257 status = pvfs_access_check_create(pvfs, req, name, &access_mask, true, &sd);
259 NT_STATUS_NOT_OK_RETURN(status);
261 if (io->generic.in.query_maximal_access) {
262 status = pvfs_access_maximal_allowed(pvfs, req, name,
263 &io->generic.out.maximal_access);
264 NT_STATUS_NOT_OK_RETURN(status);
267 f->ntvfs = h;
268 f->pvfs = pvfs;
269 f->pending_list = NULL;
270 f->lock_count = 0;
271 f->share_access = io->generic.in.share_access;
272 f->impersonation = io->generic.in.impersonation;
273 f->access_mask = access_mask;
274 f->brl_handle = NULL;
275 f->notify_buffer = NULL;
276 f->search = NULL;
278 f->handle->pvfs = pvfs;
279 f->handle->name = talloc_steal(f->handle, name);
280 f->handle->fd = -1;
281 f->handle->odb_locking_key = data_blob(NULL, 0);
282 f->handle->create_options = io->generic.in.create_options;
283 f->handle->private_flags = io->generic.in.private_flags;
284 f->handle->seek_offset = 0;
285 f->handle->position = 0;
286 f->handle->mode = 0;
287 f->handle->oplock = NULL;
288 ZERO_STRUCT(f->handle->write_time);
289 f->handle->open_completed = false;
291 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
292 pvfs_directory_empty(pvfs, f->handle->name)) {
293 del_on_close = true;
294 } else {
295 del_on_close = false;
298 if (name->exists) {
299 /* form the lock context used for opendb locking */
300 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
301 if (!NT_STATUS_IS_OK(status)) {
302 return status;
305 /* get a lock on this file before the actual open */
306 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
307 if (lck == NULL) {
308 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
309 name->full_name));
310 /* we were supposed to do a blocking lock, so something
311 is badly wrong! */
312 return NT_STATUS_INTERNAL_DB_CORRUPTION;
315 /* see if we are allowed to open at the same time as existing opens */
316 status = odb_can_open(lck, name->stream_id,
317 share_access, access_mask, del_on_close,
318 io->generic.in.open_disposition, false);
319 if (!NT_STATUS_IS_OK(status)) {
320 talloc_free(lck);
321 return status;
324 /* now really mark the file as open */
325 status = odb_open_file(lck, f->handle, name->full_name,
326 NULL, name->dos.write_time,
327 false, OPLOCK_NONE, NULL);
329 if (!NT_STATUS_IS_OK(status)) {
330 talloc_free(lck);
331 return status;
334 f->handle->have_opendb_entry = true;
337 DLIST_ADD(pvfs->files.list, f);
339 /* setup destructors to avoid leaks on abnormal termination */
340 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
341 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
343 if (!name->exists) {
344 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
345 mode_t mode = pvfs_fileperms(pvfs, attrib);
347 if (pvfs_sys_mkdir(pvfs, name->full_name, mode) == -1) {
348 return pvfs_map_errno(pvfs,errno);
351 pvfs_xattr_unlink_hook(pvfs, name->full_name);
353 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
354 if (!NT_STATUS_IS_OK(status)) {
355 goto cleanup_delete;
358 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io, sd);
359 if (!NT_STATUS_IS_OK(status)) {
360 goto cleanup_delete;
363 /* form the lock context used for opendb locking */
364 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
365 if (!NT_STATUS_IS_OK(status)) {
366 return status;
369 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
370 if (lck == NULL) {
371 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
372 name->full_name));
373 /* we were supposed to do a blocking lock, so something
374 is badly wrong! */
375 return NT_STATUS_INTERNAL_DB_CORRUPTION;
378 status = odb_can_open(lck, name->stream_id,
379 share_access, access_mask, del_on_close,
380 io->generic.in.open_disposition, false);
382 if (!NT_STATUS_IS_OK(status)) {
383 goto cleanup_delete;
386 status = odb_open_file(lck, f->handle, name->full_name,
387 NULL, name->dos.write_time,
388 false, OPLOCK_NONE, NULL);
390 if (!NT_STATUS_IS_OK(status)) {
391 goto cleanup_delete;
394 f->handle->have_opendb_entry = true;
396 create_action = NTCREATEX_ACTION_CREATED;
398 notify_trigger(pvfs->notify_context,
399 NOTIFY_ACTION_ADDED,
400 FILE_NOTIFY_CHANGE_DIR_NAME,
401 name->full_name);
402 } else {
403 create_action = NTCREATEX_ACTION_EXISTED;
406 if (!name->exists) {
407 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
410 /* the open succeeded, keep this handle permanently */
411 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
412 if (!NT_STATUS_IS_OK(status)) {
413 goto cleanup_delete;
416 f->handle->open_completed = true;
418 io->generic.out.oplock_level = OPLOCK_NONE;
419 io->generic.out.file.ntvfs = h;
420 io->generic.out.create_action = create_action;
421 io->generic.out.create_time = name->dos.create_time;
422 io->generic.out.access_time = name->dos.access_time;
423 io->generic.out.write_time = name->dos.write_time;
424 io->generic.out.change_time = name->dos.change_time;
425 io->generic.out.attrib = name->dos.attrib;
426 io->generic.out.alloc_size = name->dos.alloc_size;
427 io->generic.out.size = name->st.st_size;
428 io->generic.out.file_type = FILE_TYPE_DISK;
429 io->generic.out.ipc_state = 0;
430 io->generic.out.is_directory = 1;
432 return NT_STATUS_OK;
434 cleanup_delete:
435 pvfs_sys_rmdir(pvfs, name->full_name);
436 return status;
440 destroy a struct pvfs_file_handle
442 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
444 talloc_free(h->write_time.update_event);
445 h->write_time.update_event = NULL;
447 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
448 h->name->stream_name) {
449 NTSTATUS status;
450 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
451 if (!NT_STATUS_IS_OK(status)) {
452 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
453 h->name->stream_name, h->name->full_name));
457 if (h->fd != -1) {
458 if (close(h->fd) != 0) {
459 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
460 h->fd, h->name->full_name, strerror(errno)));
462 h->fd = -1;
465 if (!h->write_time.update_forced &&
466 h->write_time.update_on_close &&
467 h->write_time.close_time == 0) {
468 struct timeval tv;
469 tv = timeval_current();
470 h->write_time.close_time = timeval_to_nttime(&tv);
473 if (h->have_opendb_entry) {
474 struct odb_lock *lck;
475 NTSTATUS status;
476 const char *delete_path = NULL;
478 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
479 if (lck == NULL) {
480 DEBUG(0,("Unable to lock opendb for close\n"));
481 return 0;
484 if (h->write_time.update_forced) {
485 status = odb_get_file_infos(h->pvfs->odb_context,
486 &h->odb_locking_key,
487 NULL,
488 &h->write_time.close_time);
489 if (!NT_STATUS_IS_OK(status)) {
490 DEBUG(0,("Unable get write time for '%s' - %s\n",
491 h->name->full_name, nt_errstr(status)));
494 h->write_time.update_forced = false;
495 h->write_time.update_on_close = true;
496 } else if (h->write_time.update_on_close) {
497 status = odb_set_write_time(lck, h->write_time.close_time, true);
498 if (!NT_STATUS_IS_OK(status)) {
499 DEBUG(0,("Unable set write time for '%s' - %s\n",
500 h->name->full_name, nt_errstr(status)));
504 status = odb_close_file(lck, h, &delete_path);
505 if (!NT_STATUS_IS_OK(status)) {
506 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
507 h->name->full_name, nt_errstr(status)));
510 if (h->name->stream_name == NULL &&
511 h->open_completed && delete_path) {
512 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
513 if (!NT_STATUS_IS_OK(status)) {
514 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
515 delete_path, nt_errstr(status)));
517 if (pvfs_sys_unlink(h->pvfs, delete_path) != 0) {
518 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
519 delete_path, strerror(errno)));
520 } else {
521 notify_trigger(h->pvfs->notify_context,
522 NOTIFY_ACTION_REMOVED,
523 FILE_NOTIFY_CHANGE_FILE_NAME,
524 delete_path);
526 h->write_time.update_on_close = false;
529 talloc_free(lck);
532 if (h->write_time.update_on_close) {
533 struct timeval tv[2];
535 nttime_to_timeval(&tv[0], h->name->dos.access_time);
536 nttime_to_timeval(&tv[1], h->write_time.close_time);
538 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
539 if (utimes(h->name->full_name, tv) == -1) {
540 DEBUG(3,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
541 h->name->full_name, strerror(errno)));
546 return 0;
551 destroy a struct pvfs_file
553 static int pvfs_fnum_destructor(struct pvfs_file *f)
555 DLIST_REMOVE(f->pvfs->files.list, f);
556 pvfs_lock_close(f->pvfs, f);
557 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
559 return 0;
564 form the lock context used for byte range locking. This is separate
565 from the locking key used for opendb locking as it needs to take
566 account of file streams (each stream is a separate byte range
567 locking space)
569 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
570 struct pvfs_filename *name,
571 struct ntvfs_handle *ntvfs,
572 struct brl_handle **_h)
574 DATA_BLOB odb_key, key;
575 NTSTATUS status;
576 struct brl_handle *h;
578 status = pvfs_locking_key(name, mem_ctx, &odb_key);
579 NT_STATUS_NOT_OK_RETURN(status);
581 if (name->stream_name == NULL) {
582 key = odb_key;
583 } else {
584 key = data_blob_talloc(mem_ctx, NULL,
585 odb_key.length + strlen(name->stream_name) + 1);
586 NT_STATUS_HAVE_NO_MEMORY(key.data);
587 memcpy(key.data, odb_key.data, odb_key.length);
588 memcpy(key.data + odb_key.length,
589 name->stream_name, strlen(name->stream_name) + 1);
590 data_blob_free(&odb_key);
593 h = brl_create_handle(mem_ctx, ntvfs, &key);
594 NT_STATUS_HAVE_NO_MEMORY(h);
596 *_h = h;
597 return NT_STATUS_OK;
601 create a new file
603 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
604 struct ntvfs_request *req,
605 struct pvfs_filename *name,
606 union smb_open *io)
608 struct pvfs_file *f;
609 NTSTATUS status;
610 struct ntvfs_handle *h;
611 int flags, fd;
612 struct odb_lock *lck;
613 uint32_t create_options = io->generic.in.create_options;
614 uint32_t share_access = io->generic.in.share_access;
615 uint32_t access_mask = io->generic.in.access_mask;
616 mode_t mode;
617 uint32_t attrib;
618 bool del_on_close;
619 struct pvfs_filename *parent;
620 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
621 bool allow_level_II_oplock = false;
622 struct security_descriptor *sd = NULL;
624 if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
625 DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
626 io->ntcreatex.in.file_attr, name->original_name));
627 return NT_STATUS_INVALID_PARAMETER;
630 if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
631 DEBUG(3,(__location__ ": Invalid encryption request for %s\n",
632 name->original_name));
633 return NT_STATUS_ACCESS_DENIED;
636 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
637 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
638 DEBUG(4,(__location__ ": Invalid delete on close for readonly file %s\n",
639 name->original_name));
640 return NT_STATUS_CANNOT_DELETE;
643 sd = io->ntcreatex.in.sec_desc;
644 status = pvfs_access_check_create(pvfs, req, name, &access_mask, false, &sd);
645 NT_STATUS_NOT_OK_RETURN(status);
647 /* check that the parent isn't opened with delete on close set */
648 status = pvfs_resolve_parent(pvfs, req, name, &parent);
649 if (NT_STATUS_IS_OK(status)) {
650 DATA_BLOB locking_key;
651 status = pvfs_locking_key(parent, req, &locking_key);
652 NT_STATUS_NOT_OK_RETURN(status);
653 status = odb_get_file_infos(pvfs->odb_context, &locking_key,
654 &del_on_close, NULL);
655 NT_STATUS_NOT_OK_RETURN(status);
656 if (del_on_close) {
657 return NT_STATUS_DELETE_PENDING;
661 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
662 flags = O_RDWR;
663 } else {
664 flags = O_RDONLY;
667 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
668 NT_STATUS_NOT_OK_RETURN(status);
670 f = talloc(h, struct pvfs_file);
671 NT_STATUS_HAVE_NO_MEMORY(f);
673 f->handle = talloc(f, struct pvfs_file_handle);
674 NT_STATUS_HAVE_NO_MEMORY(f->handle);
676 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
677 mode = pvfs_fileperms(pvfs, attrib);
679 /* create the file */
680 fd = pvfs_sys_open(pvfs, name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
681 if (fd == -1) {
682 return pvfs_map_errno(pvfs, errno);
685 pvfs_xattr_unlink_hook(pvfs, name->full_name);
687 /* if this was a stream create then create the stream as well */
688 if (name->stream_name) {
689 status = pvfs_stream_create(pvfs, name, fd);
690 if (!NT_STATUS_IS_OK(status)) {
691 close(fd);
692 return status;
696 /* re-resolve the open fd */
697 status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
698 if (!NT_STATUS_IS_OK(status)) {
699 close(fd);
700 return status;
703 /* support initial alloc sizes */
704 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
705 name->dos.attrib = attrib;
706 status = pvfs_dosattrib_save(pvfs, name, fd);
707 if (!NT_STATUS_IS_OK(status)) {
708 goto cleanup_delete;
712 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io, sd);
713 if (!NT_STATUS_IS_OK(status)) {
714 goto cleanup_delete;
717 if (io->generic.in.query_maximal_access) {
718 status = pvfs_access_maximal_allowed(pvfs, req, name,
719 &io->generic.out.maximal_access);
720 NT_STATUS_NOT_OK_RETURN(status);
723 /* form the lock context used for byte range locking and
724 opendb locking */
725 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
726 if (!NT_STATUS_IS_OK(status)) {
727 goto cleanup_delete;
730 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
731 if (!NT_STATUS_IS_OK(status)) {
732 goto cleanup_delete;
735 /* grab a lock on the open file record */
736 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
737 if (lck == NULL) {
738 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
739 name->full_name));
740 /* we were supposed to do a blocking lock, so something
741 is badly wrong! */
742 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
743 goto cleanup_delete;
746 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
747 del_on_close = true;
748 } else {
749 del_on_close = false;
752 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
753 oplock_level = OPLOCK_NONE;
754 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
755 oplock_level = OPLOCK_BATCH;
756 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
757 oplock_level = OPLOCK_EXCLUSIVE;
760 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
761 allow_level_II_oplock = true;
764 status = odb_can_open(lck, name->stream_id,
765 share_access, access_mask, del_on_close,
766 io->generic.in.open_disposition, false);
767 if (!NT_STATUS_IS_OK(status)) {
768 talloc_free(lck);
769 /* bad news, we must have hit a race - we don't delete the file
770 here as the most likely scenario is that someone else created
771 the file at the same time */
772 close(fd);
773 return status;
776 f->ntvfs = h;
777 f->pvfs = pvfs;
778 f->pending_list = NULL;
779 f->lock_count = 0;
780 f->share_access = io->generic.in.share_access;
781 f->access_mask = access_mask;
782 f->impersonation = io->generic.in.impersonation;
783 f->notify_buffer = NULL;
784 f->search = NULL;
786 f->handle->pvfs = pvfs;
787 f->handle->name = talloc_steal(f->handle, name);
788 f->handle->fd = fd;
789 f->handle->create_options = io->generic.in.create_options;
790 f->handle->private_flags = io->generic.in.private_flags;
791 f->handle->seek_offset = 0;
792 f->handle->position = 0;
793 f->handle->mode = 0;
794 f->handle->oplock = NULL;
795 f->handle->have_opendb_entry = true;
796 ZERO_STRUCT(f->handle->write_time);
797 f->handle->open_completed = false;
799 status = odb_open_file(lck, f->handle, name->full_name,
800 &f->handle->fd, name->dos.write_time,
801 allow_level_II_oplock,
802 oplock_level, &oplock_granted);
803 talloc_free(lck);
804 if (!NT_STATUS_IS_OK(status)) {
805 /* bad news, we must have hit a race - we don't delete the file
806 here as the most likely scenario is that someone else created
807 the file at the same time */
808 close(fd);
809 return status;
812 DLIST_ADD(pvfs->files.list, f);
814 /* setup a destructor to avoid file descriptor leaks on
815 abnormal termination */
816 talloc_set_destructor(f, pvfs_fnum_destructor);
817 talloc_set_destructor(f->handle, pvfs_handle_destructor);
819 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
820 oplock_granted = OPLOCK_BATCH;
821 } else if (oplock_granted != OPLOCK_NONE) {
822 status = pvfs_setup_oplock(f, oplock_granted);
823 if (!NT_STATUS_IS_OK(status)) {
824 return status;
828 io->generic.out.oplock_level = oplock_granted;
829 io->generic.out.file.ntvfs = f->ntvfs;
830 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
831 io->generic.out.create_time = name->dos.create_time;
832 io->generic.out.access_time = name->dos.access_time;
833 io->generic.out.write_time = name->dos.write_time;
834 io->generic.out.change_time = name->dos.change_time;
835 io->generic.out.attrib = name->dos.attrib;
836 io->generic.out.alloc_size = name->dos.alloc_size;
837 io->generic.out.size = name->st.st_size;
838 io->generic.out.file_type = FILE_TYPE_DISK;
839 io->generic.out.ipc_state = 0;
840 io->generic.out.is_directory = 0;
842 /* success - keep the file handle */
843 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
844 if (!NT_STATUS_IS_OK(status)) {
845 goto cleanup_delete;
848 f->handle->open_completed = true;
850 notify_trigger(pvfs->notify_context,
851 NOTIFY_ACTION_ADDED,
852 FILE_NOTIFY_CHANGE_FILE_NAME,
853 name->full_name);
855 return NT_STATUS_OK;
857 cleanup_delete:
858 close(fd);
859 pvfs_sys_unlink(pvfs, name->full_name);
860 return status;
864 state of a pending retry
866 struct pvfs_odb_retry {
867 struct ntvfs_module_context *ntvfs;
868 struct ntvfs_request *req;
869 DATA_BLOB odb_locking_key;
870 void *io;
871 void *private_data;
872 void (*callback)(struct pvfs_odb_retry *r,
873 struct ntvfs_module_context *ntvfs,
874 struct ntvfs_request *req,
875 void *io,
876 void *private_data,
877 enum pvfs_wait_notice reason);
880 /* destroy a pending request */
881 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
883 struct pvfs_state *pvfs = talloc_get_type(r->ntvfs->private_data,
884 struct pvfs_state);
885 if (r->odb_locking_key.data) {
886 struct odb_lock *lck;
887 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
888 if (lck != NULL) {
889 odb_remove_pending(lck, r);
891 talloc_free(lck);
893 return 0;
896 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
898 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
900 if (reason == PVFS_WAIT_EVENT) {
902 * The pending odb entry is already removed.
903 * We use a null locking key to indicate this
904 * to the destructor.
906 data_blob_free(&r->odb_locking_key);
909 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
913 setup for a retry of a request that was rejected
914 by odb_can_open()
916 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
917 struct ntvfs_request *req,
918 struct odb_lock *lck,
919 struct timeval end_time,
920 void *io,
921 void *private_data,
922 void (*callback)(struct pvfs_odb_retry *r,
923 struct ntvfs_module_context *ntvfs,
924 struct ntvfs_request *req,
925 void *io,
926 void *private_data,
927 enum pvfs_wait_notice reason))
929 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
930 struct pvfs_state);
931 struct pvfs_odb_retry *r;
932 struct pvfs_wait *wait_handle;
933 NTSTATUS status;
935 r = talloc(req, struct pvfs_odb_retry);
936 NT_STATUS_HAVE_NO_MEMORY(r);
938 r->ntvfs = ntvfs;
939 r->req = req;
940 r->io = io;
941 r->private_data = private_data;
942 r->callback = callback;
943 r->odb_locking_key = odb_get_key(r, lck);
944 if (r->odb_locking_key.data == NULL) {
945 return NT_STATUS_NO_MEMORY;
948 /* setup a pending lock */
949 status = odb_open_file_pending(lck, r);
950 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
952 * maybe only a unix application
953 * has the file open
955 data_blob_free(&r->odb_locking_key);
956 } else if (!NT_STATUS_IS_OK(status)) {
957 return status;
960 talloc_free(lck);
962 talloc_set_destructor(r, pvfs_odb_retry_destructor);
964 wait_handle = pvfs_wait_message(pvfs, req,
965 MSG_PVFS_RETRY_OPEN, end_time,
966 pvfs_odb_retry_callback, r);
967 if (wait_handle == NULL) {
968 return NT_STATUS_NO_MEMORY;
971 talloc_steal(r, wait_handle);
973 return NT_STATUS_OK;
977 retry an open after a sharing violation
979 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
980 struct ntvfs_module_context *ntvfs,
981 struct ntvfs_request *req,
982 void *_io,
983 void *private_data,
984 enum pvfs_wait_notice reason)
986 union smb_open *io = talloc_get_type(_io, union smb_open);
987 struct timeval *final_timeout = NULL;
988 NTSTATUS status;
990 if (private_data) {
991 final_timeout = talloc_get_type(private_data,
992 struct timeval);
995 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
996 just a bug in their server, but we better do the same */
997 if (reason == PVFS_WAIT_CANCEL) {
998 return;
1001 if (reason == PVFS_WAIT_TIMEOUT) {
1002 if (final_timeout &&
1003 !timeval_expired(final_timeout)) {
1005 * we need to retry periodictly
1006 * after an EAGAIN as there's
1007 * no way the kernel tell us
1008 * an oplock is released.
1010 goto retry;
1012 /* if it timed out, then give the failure
1013 immediately */
1014 talloc_free(r);
1015 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
1016 req->async_states->send_fn(req);
1017 return;
1020 retry:
1021 talloc_free(r);
1023 /* try the open again, which could trigger another retry setup
1024 if it wants to, so we have to unmark the async flag so we
1025 will know if it does a second async reply */
1026 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
1028 status = pvfs_open(ntvfs, req, io);
1029 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
1030 /* the 2nd try also replied async, so we don't send
1031 the reply yet */
1032 return;
1035 /* re-mark it async, just in case someone up the chain does
1036 paranoid checking */
1037 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1039 /* send the reply up the chain */
1040 req->async_states->status = status;
1041 req->async_states->send_fn(req);
1046 special handling for openx DENY_DOS semantics
1048 This function attempts a reference open using an existing handle. If its allowed,
1049 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
1050 open processing continues.
1052 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
1053 struct ntvfs_request *req, union smb_open *io,
1054 struct pvfs_file *f, struct odb_lock *lck)
1056 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1057 struct pvfs_state);
1058 struct pvfs_file *f2;
1059 struct pvfs_filename *name;
1060 NTSTATUS status;
1062 /* search for an existing open with the right parameters. Note
1063 the magic ntcreatex options flag, which is set in the
1064 generic mapping code. This might look ugly, but its
1065 actually pretty much now w2k does it internally as well.
1067 If you look at the BASE-DENYDOS test you will see that a
1068 DENY_DOS is a very special case, and in the right
1069 circumstances you actually get the _same_ handle back
1070 twice, rather than a new handle.
1072 for (f2=pvfs->files.list;f2;f2=f2->next) {
1073 if (f2 != f &&
1074 f2->ntvfs->session_info == req->session_info &&
1075 f2->ntvfs->smbpid == req->smbpid &&
1076 (f2->handle->private_flags &
1077 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
1078 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
1079 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1080 strcasecmp_m(f2->handle->name->original_name,
1081 io->generic.in.fname)==0) {
1082 break;
1086 if (!f2) {
1087 return NT_STATUS_SHARING_VIOLATION;
1090 /* quite an insane set of semantics ... */
1091 if (is_exe_filename(io->generic.in.fname) &&
1092 (f2->handle->private_flags & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1093 return NT_STATUS_SHARING_VIOLATION;
1097 setup a reference to the existing handle
1099 talloc_free(f->handle);
1100 f->handle = talloc_reference(f, f2->handle);
1102 talloc_free(lck);
1104 name = f->handle->name;
1106 io->generic.out.oplock_level = OPLOCK_NONE;
1107 io->generic.out.file.ntvfs = f->ntvfs;
1108 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1109 io->generic.out.create_time = name->dos.create_time;
1110 io->generic.out.access_time = name->dos.access_time;
1111 io->generic.out.write_time = name->dos.write_time;
1112 io->generic.out.change_time = name->dos.change_time;
1113 io->generic.out.attrib = name->dos.attrib;
1114 io->generic.out.alloc_size = name->dos.alloc_size;
1115 io->generic.out.size = name->st.st_size;
1116 io->generic.out.file_type = FILE_TYPE_DISK;
1117 io->generic.out.ipc_state = 0;
1118 io->generic.out.is_directory = 0;
1120 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1121 NT_STATUS_NOT_OK_RETURN(status);
1123 return NT_STATUS_OK;
1129 setup for a open retry after a sharing violation
1131 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1132 struct ntvfs_request *req,
1133 union smb_open *io,
1134 struct pvfs_file *f,
1135 struct odb_lock *lck,
1136 NTSTATUS parent_status)
1138 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1139 struct pvfs_state);
1140 NTSTATUS status;
1141 struct timeval end_time;
1142 struct timeval *final_timeout = NULL;
1144 if (io->generic.in.private_flags &
1145 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1146 /* see if we can satisfy the request using the special DENY_DOS
1147 code */
1148 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1149 if (NT_STATUS_IS_OK(status)) {
1150 return status;
1154 /* the retry should allocate a new file handle */
1155 talloc_free(f);
1157 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1158 end_time = timeval_add(&req->statistics.request_time,
1159 0, pvfs->sharing_violation_delay);
1160 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1161 end_time = timeval_add(&req->statistics.request_time,
1162 pvfs->oplock_break_timeout, 0);
1163 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1165 * we got EAGAIN which means a unix application
1166 * has an oplock or share mode
1168 * we retry every 4/5 of the sharing violation delay
1169 * to see if the unix application
1170 * has released the oplock or share mode.
1172 final_timeout = talloc(req, struct timeval);
1173 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1174 *final_timeout = timeval_add(&req->statistics.request_time,
1175 pvfs->oplock_break_timeout,
1177 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1178 end_time = timeval_min(final_timeout, &end_time);
1179 } else {
1180 return NT_STATUS_INTERNAL_ERROR;
1183 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1184 final_timeout, pvfs_retry_open_sharing);
1188 open a file
1190 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1191 struct ntvfs_request *req, union smb_open *io)
1193 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1194 struct pvfs_state);
1195 int flags = 0;
1196 struct pvfs_filename *name;
1197 struct pvfs_file *f;
1198 struct ntvfs_handle *h;
1199 NTSTATUS status;
1200 int fd;
1201 struct odb_lock *lck;
1202 uint32_t create_options;
1203 uint32_t create_options_must_ignore_mask;
1204 uint32_t share_access;
1205 uint32_t access_mask;
1206 uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1207 bool del_on_close;
1208 bool stream_existed, stream_truncate=false;
1209 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1210 bool allow_level_II_oplock = false;
1212 /* use the generic mapping code to avoid implementing all the
1213 different open calls. */
1214 if (io->generic.level != RAW_OPEN_GENERIC &&
1215 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1216 return ntvfs_map_open(ntvfs, req, io);
1219 ZERO_STRUCT(io->generic.out);
1221 create_options = io->generic.in.create_options;
1222 share_access = io->generic.in.share_access;
1223 access_mask = io->generic.in.access_mask;
1225 if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1226 DEBUG(3,(__location__ ": Invalid share_access 0x%08x for %s\n",
1227 share_access, io->ntcreatex.in.fname));
1228 return NT_STATUS_INVALID_PARAMETER;
1232 * These options are ignored,
1233 * but we reuse some of them as private values for the generic mapping
1235 create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
1236 create_options &= ~create_options_must_ignore_mask;
1238 if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1239 DEBUG(2,(__location__ " create_options 0x%x not supported\n",
1240 create_options));
1241 return NT_STATUS_NOT_SUPPORTED;
1244 if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
1245 DEBUG(3,(__location__ ": Invalid create_options 0x%08x for %s\n",
1246 create_options, io->ntcreatex.in.fname));
1247 return NT_STATUS_INVALID_PARAMETER;
1250 /* TODO: When we implement HSM, add a hook here not to pull
1251 * the actual file off tape, when this option is passed from
1252 * the client */
1253 if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1254 /* no-op */
1257 /* TODO: If (unlikely) Linux does a good compressed
1258 * filesystem, we might need an ioctl call for this */
1259 if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
1260 /* no-op */
1263 if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
1264 create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
1267 /* Open the file with sync, if they asked for it, but
1268 'strict sync = no' turns this client request into a no-op */
1269 if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && !(pvfs->flags | PVFS_FLAG_STRICT_SYNC)) {
1270 flags |= O_SYNC;
1274 /* other create options are not allowed */
1275 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1276 !(access_mask & SEC_STD_DELETE)) {
1277 DEBUG(3,(__location__ ": Invalid delete_on_close option 0x%08x with access_mask 0x%08x for %s\n",
1278 create_options, access_mask, io->ntcreatex.in.fname));
1279 return NT_STATUS_INVALID_PARAMETER;
1282 if (access_mask & SEC_MASK_INVALID) {
1283 return NT_STATUS_ACCESS_DENIED;
1286 /* what does this bit really mean?? */
1287 if (req->ctx->protocol == PROTOCOL_SMB2 &&
1288 access_mask == SEC_STD_SYNCHRONIZE) {
1289 return NT_STATUS_ACCESS_DENIED;
1292 /* cope with non-zero root_fid */
1293 if (io->ntcreatex.in.root_fid.ntvfs != NULL) {
1294 f = pvfs_find_fd(pvfs, req, io->ntcreatex.in.root_fid.ntvfs);
1295 if (f == NULL) {
1296 return NT_STATUS_INVALID_HANDLE;
1298 if (f->handle->fd != -1) {
1299 return NT_STATUS_INVALID_DEVICE_REQUEST;
1301 io->ntcreatex.in.fname = talloc_asprintf(req, "%s\\%s",
1302 f->handle->name->original_name,
1303 io->ntcreatex.in.fname);
1304 NT_STATUS_HAVE_NO_MEMORY(io->ntcreatex.in.fname);
1307 if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1308 FILE_ATTRIBUTE_VOLUME|
1309 (~FILE_ATTRIBUTE_ALL_MASK))) {
1310 DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
1311 io->ntcreatex.in.file_attr, io->ntcreatex.in.fname));
1312 return NT_STATUS_INVALID_PARAMETER;
1315 /* we ignore some file_attr bits */
1316 io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED |
1317 FILE_ATTRIBUTE_COMPRESSED |
1318 FILE_ATTRIBUTE_REPARSE_POINT |
1319 FILE_ATTRIBUTE_SPARSE |
1320 FILE_ATTRIBUTE_NORMAL);
1322 /* resolve the cifs name to a posix name */
1323 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1324 PVFS_RESOLVE_STREAMS, &name);
1325 if (!NT_STATUS_IS_OK(status)) {
1326 return status;
1329 /* if the client specified that it must not be a directory then
1330 check that it isn't */
1331 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1332 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1333 return NT_STATUS_FILE_IS_A_DIRECTORY;
1336 /* if the client specified that it must be a directory then
1337 check that it is */
1338 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1339 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1340 return NT_STATUS_NOT_A_DIRECTORY;
1343 /* directory opens are handled separately */
1344 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1345 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1346 return pvfs_open_directory(pvfs, req, name, io);
1349 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1350 open doesn't match */
1351 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1353 switch (io->generic.in.open_disposition) {
1354 case NTCREATEX_DISP_SUPERSEDE:
1355 case NTCREATEX_DISP_OVERWRITE_IF:
1356 if (name->stream_name == NULL) {
1357 flags = O_TRUNC;
1358 } else {
1359 stream_truncate = true;
1361 create_action = NTCREATEX_ACTION_TRUNCATED;
1362 break;
1364 case NTCREATEX_DISP_OPEN:
1365 if (!name->stream_exists) {
1366 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1368 flags = 0;
1369 break;
1371 case NTCREATEX_DISP_OVERWRITE:
1372 if (!name->stream_exists) {
1373 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1375 if (name->stream_name == NULL) {
1376 flags = O_TRUNC;
1377 } else {
1378 stream_truncate = true;
1380 create_action = NTCREATEX_ACTION_TRUNCATED;
1381 break;
1383 case NTCREATEX_DISP_CREATE:
1384 if (name->stream_exists) {
1385 return NT_STATUS_OBJECT_NAME_COLLISION;
1387 flags = 0;
1388 break;
1390 case NTCREATEX_DISP_OPEN_IF:
1391 flags = 0;
1392 break;
1394 default:
1395 DEBUG(3,(__location__ ": Invalid open disposition 0x%08x for %s\n",
1396 io->generic.in.open_disposition, name->original_name));
1397 return NT_STATUS_INVALID_PARAMETER;
1400 /* handle creating a new file separately */
1401 if (!name->exists) {
1402 status = pvfs_create_file(pvfs, req, name, io);
1403 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1404 return status;
1407 /* we've hit a race - the file was created during this call */
1408 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1409 return status;
1412 /* try re-resolving the name */
1413 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1414 if (!NT_STATUS_IS_OK(status)) {
1415 return status;
1417 /* fall through to a normal open */
1420 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1421 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1422 return NT_STATUS_CANNOT_DELETE;
1425 /* check the security descriptor */
1426 status = pvfs_access_check(pvfs, req, name, &access_mask);
1427 NT_STATUS_NOT_OK_RETURN(status);
1429 if (io->generic.in.query_maximal_access) {
1430 status = pvfs_access_maximal_allowed(pvfs, req, name,
1431 &io->generic.out.maximal_access);
1432 NT_STATUS_NOT_OK_RETURN(status);
1435 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1436 NT_STATUS_NOT_OK_RETURN(status);
1438 f = talloc(h, struct pvfs_file);
1439 if (f == NULL) {
1440 return NT_STATUS_NO_MEMORY;
1443 f->handle = talloc(f, struct pvfs_file_handle);
1444 if (f->handle == NULL) {
1445 return NT_STATUS_NO_MEMORY;
1448 f->ntvfs = h;
1449 f->pvfs = pvfs;
1450 f->pending_list = NULL;
1451 f->lock_count = 0;
1452 f->share_access = io->generic.in.share_access;
1453 f->access_mask = access_mask;
1454 f->impersonation = io->generic.in.impersonation;
1455 f->notify_buffer = NULL;
1456 f->search = NULL;
1458 f->handle->pvfs = pvfs;
1459 f->handle->fd = -1;
1460 f->handle->name = talloc_steal(f->handle, name);
1461 f->handle->create_options = io->generic.in.create_options;
1462 f->handle->private_flags = io->generic.in.private_flags;
1463 f->handle->seek_offset = 0;
1464 f->handle->position = 0;
1465 f->handle->mode = 0;
1466 f->handle->oplock = NULL;
1467 f->handle->have_opendb_entry = false;
1468 ZERO_STRUCT(f->handle->write_time);
1469 f->handle->open_completed = false;
1471 /* form the lock context used for byte range locking and
1472 opendb locking */
1473 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1474 if (!NT_STATUS_IS_OK(status)) {
1475 return status;
1478 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1479 if (!NT_STATUS_IS_OK(status)) {
1480 return status;
1483 /* get a lock on this file before the actual open */
1484 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1485 if (lck == NULL) {
1486 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1487 name->full_name));
1488 /* we were supposed to do a blocking lock, so something
1489 is badly wrong! */
1490 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1493 DLIST_ADD(pvfs->files.list, f);
1495 /* setup a destructor to avoid file descriptor leaks on
1496 abnormal termination */
1497 talloc_set_destructor(f, pvfs_fnum_destructor);
1498 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1501 * Only SMB2 takes care of the delete_on_close,
1502 * on existing files
1504 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1505 req->ctx->protocol == PROTOCOL_SMB2) {
1506 del_on_close = true;
1507 } else {
1508 del_on_close = false;
1511 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1512 oplock_level = OPLOCK_NONE;
1513 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1514 oplock_level = OPLOCK_BATCH;
1515 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1516 oplock_level = OPLOCK_EXCLUSIVE;
1519 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1520 allow_level_II_oplock = true;
1523 /* see if we are allowed to open at the same time as existing opens */
1524 status = odb_can_open(lck, name->stream_id,
1525 share_access, access_mask, del_on_close,
1526 io->generic.in.open_disposition, false);
1529 * on a sharing violation we need to retry when the file is closed by
1530 * the other user, or after 1 second
1531 * on a non granted oplock we need to retry when the file is closed by
1532 * the other user, or after 30 seconds
1534 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1535 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1536 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1537 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1540 if (!NT_STATUS_IS_OK(status)) {
1541 talloc_free(lck);
1542 return status;
1545 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1546 flags |= O_RDWR;
1547 } else {
1548 flags |= O_RDONLY;
1551 /* do the actual open */
1552 fd = pvfs_sys_open(pvfs, f->handle->name->full_name, flags | O_NONBLOCK, 0);
1553 if (fd == -1) {
1554 status = pvfs_map_errno(f->pvfs, errno);
1556 DEBUG(0,(__location__ " mapped errno %s for %s (was %d)\n",
1557 nt_errstr(status), f->handle->name->full_name, errno));
1559 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1561 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1562 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1563 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1566 talloc_free(lck);
1567 return status;
1570 f->handle->fd = fd;
1572 /* now really mark the file as open */
1573 status = odb_open_file(lck, f->handle, name->full_name,
1574 &f->handle->fd, name->dos.write_time,
1575 allow_level_II_oplock,
1576 oplock_level, &oplock_granted);
1578 if (!NT_STATUS_IS_OK(status)) {
1579 talloc_free(lck);
1580 return status;
1583 f->handle->have_opendb_entry = true;
1585 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1586 oplock_granted = OPLOCK_BATCH;
1587 } else if (oplock_granted != OPLOCK_NONE) {
1588 status = pvfs_setup_oplock(f, oplock_granted);
1589 if (!NT_STATUS_IS_OK(status)) {
1590 talloc_free(lck);
1591 return status;
1595 stream_existed = name->stream_exists;
1597 /* if this was a stream create then create the stream as well */
1598 if (!name->stream_exists) {
1599 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1600 if (!NT_STATUS_IS_OK(status)) {
1601 talloc_free(lck);
1602 return status;
1604 if (stream_truncate) {
1605 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1606 if (!NT_STATUS_IS_OK(status)) {
1607 talloc_free(lck);
1608 return status;
1613 /* re-resolve the open fd */
1614 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1615 if (!NT_STATUS_IS_OK(status)) {
1616 talloc_free(lck);
1617 return status;
1620 if (f->handle->name->stream_id == 0 &&
1621 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1622 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1623 /* for overwrite we may need to replace file permissions */
1624 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1625 mode_t mode = pvfs_fileperms(pvfs, attrib);
1626 if (f->handle->name->st.st_mode != mode &&
1627 f->handle->name->dos.attrib != attrib &&
1628 pvfs_sys_fchmod(pvfs, fd, mode) == -1) {
1629 talloc_free(lck);
1630 return pvfs_map_errno(pvfs, errno);
1632 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1633 name->dos.attrib = attrib;
1634 status = pvfs_dosattrib_save(pvfs, name, fd);
1635 if (!NT_STATUS_IS_OK(status)) {
1636 talloc_free(lck);
1637 return status;
1641 talloc_free(lck);
1643 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1644 NT_STATUS_NOT_OK_RETURN(status);
1646 /* mark the open as having completed fully, so delete on close
1647 can now be used */
1648 f->handle->open_completed = true;
1650 io->generic.out.oplock_level = oplock_granted;
1651 io->generic.out.file.ntvfs = h;
1652 io->generic.out.create_action = stream_existed?
1653 create_action:NTCREATEX_ACTION_CREATED;
1655 io->generic.out.create_time = name->dos.create_time;
1656 io->generic.out.access_time = name->dos.access_time;
1657 io->generic.out.write_time = name->dos.write_time;
1658 io->generic.out.change_time = name->dos.change_time;
1659 io->generic.out.attrib = name->dos.attrib;
1660 io->generic.out.alloc_size = name->dos.alloc_size;
1661 io->generic.out.size = name->st.st_size;
1662 io->generic.out.file_type = FILE_TYPE_DISK;
1663 io->generic.out.ipc_state = 0;
1664 io->generic.out.is_directory = 0;
1666 return NT_STATUS_OK;
1671 close a file
1673 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1674 struct ntvfs_request *req, union smb_close *io)
1676 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1677 struct pvfs_state);
1678 struct pvfs_file *f;
1680 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1681 return NT_STATUS_DOS(ERRSRV, ERRerror);
1684 if (io->generic.level != RAW_CLOSE_GENERIC) {
1685 return ntvfs_map_close(ntvfs, req, io);
1688 f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1689 if (!f) {
1690 return NT_STATUS_INVALID_HANDLE;
1693 if (!null_time(io->generic.in.write_time)) {
1694 f->handle->write_time.update_forced = false;
1695 f->handle->write_time.update_on_close = true;
1696 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1699 if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1700 struct pvfs_filename *name;
1701 NTSTATUS status;
1702 struct pvfs_file_handle *h = f->handle;
1704 status = pvfs_resolve_name_handle(pvfs, h);
1705 if (!NT_STATUS_IS_OK(status)) {
1706 return status;
1708 name = h->name;
1710 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1711 io->generic.out.create_time = name->dos.create_time;
1712 io->generic.out.access_time = name->dos.access_time;
1713 io->generic.out.write_time = name->dos.write_time;
1714 io->generic.out.change_time = name->dos.change_time;
1715 io->generic.out.alloc_size = name->dos.alloc_size;
1716 io->generic.out.size = name->st.st_size;
1717 io->generic.out.file_attr = name->dos.attrib;
1718 } else {
1719 ZERO_STRUCT(io->generic.out);
1722 talloc_free(f);
1724 return NT_STATUS_OK;
1729 logoff - close all file descriptors open by a vuid
1731 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1732 struct ntvfs_request *req)
1734 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1735 struct pvfs_state);
1736 struct pvfs_file *f, *next;
1738 /* If pvfs is NULL, we never logged on, and no files are open. */
1739 if(pvfs == NULL) {
1740 return NT_STATUS_OK;
1743 for (f=pvfs->files.list;f;f=next) {
1744 next = f->next;
1745 if (f->ntvfs->session_info == req->session_info) {
1746 talloc_free(f);
1750 return NT_STATUS_OK;
1755 exit - close files for the current pid
1757 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1758 struct ntvfs_request *req)
1760 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1761 struct pvfs_state);
1762 struct pvfs_file *f, *next;
1764 for (f=pvfs->files.list;f;f=next) {
1765 next = f->next;
1766 if (f->ntvfs->session_info == req->session_info &&
1767 f->ntvfs->smbpid == req->smbpid) {
1768 talloc_free(f);
1772 return NT_STATUS_OK;
1777 change the delete on close flag on an already open file
1779 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1780 struct ntvfs_request *req,
1781 struct pvfs_file *f, bool del_on_close)
1783 struct odb_lock *lck;
1784 NTSTATUS status;
1786 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1787 return NT_STATUS_CANNOT_DELETE;
1790 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1791 !pvfs_directory_empty(pvfs, f->handle->name)) {
1792 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1795 if (del_on_close) {
1796 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1797 } else {
1798 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1801 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1802 if (lck == NULL) {
1803 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1806 status = odb_set_delete_on_close(lck, del_on_close);
1808 talloc_free(lck);
1810 return status;
1815 determine if a file can be deleted, or if it is prevented by an
1816 already open file
1818 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1819 struct ntvfs_request *req,
1820 struct pvfs_filename *name,
1821 struct odb_lock **lckp)
1823 NTSTATUS status;
1824 DATA_BLOB key;
1825 struct odb_lock *lck;
1826 uint32_t share_access;
1827 uint32_t access_mask;
1828 bool delete_on_close;
1830 status = pvfs_locking_key(name, name, &key);
1831 if (!NT_STATUS_IS_OK(status)) {
1832 return NT_STATUS_NO_MEMORY;
1835 lck = odb_lock(req, pvfs->odb_context, &key);
1836 if (lck == NULL) {
1837 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1838 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1841 share_access = NTCREATEX_SHARE_ACCESS_READ |
1842 NTCREATEX_SHARE_ACCESS_WRITE |
1843 NTCREATEX_SHARE_ACCESS_DELETE;
1844 access_mask = SEC_STD_DELETE;
1845 delete_on_close = true;
1847 status = odb_can_open(lck, name->stream_id,
1848 share_access, access_mask, delete_on_close,
1849 NTCREATEX_DISP_OPEN, false);
1851 if (NT_STATUS_IS_OK(status)) {
1852 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1856 * if it's a sharing violation or we got no oplock
1857 * only keep the lock if the caller requested access
1858 * to the lock
1860 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1861 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1862 if (lckp) {
1863 *lckp = lck;
1864 } else {
1865 talloc_free(lck);
1867 } else if (!NT_STATUS_IS_OK(status)) {
1868 talloc_free(lck);
1869 if (lckp) {
1870 *lckp = NULL;
1872 } else if (lckp) {
1873 *lckp = lck;
1876 return status;
1880 determine if a file can be renamed, or if it is prevented by an
1881 already open file
1883 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1884 struct ntvfs_request *req,
1885 struct pvfs_filename *name,
1886 struct odb_lock **lckp)
1888 NTSTATUS status;
1889 DATA_BLOB key;
1890 struct odb_lock *lck;
1891 uint32_t share_access;
1892 uint32_t access_mask;
1893 bool delete_on_close;
1895 status = pvfs_locking_key(name, name, &key);
1896 if (!NT_STATUS_IS_OK(status)) {
1897 return NT_STATUS_NO_MEMORY;
1900 lck = odb_lock(req, pvfs->odb_context, &key);
1901 if (lck == NULL) {
1902 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1903 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1906 share_access = NTCREATEX_SHARE_ACCESS_READ |
1907 NTCREATEX_SHARE_ACCESS_WRITE;
1908 access_mask = SEC_STD_DELETE;
1909 delete_on_close = false;
1911 status = odb_can_open(lck, name->stream_id,
1912 share_access, access_mask, delete_on_close,
1913 NTCREATEX_DISP_OPEN, false);
1916 * if it's a sharing violation or we got no oplock
1917 * only keep the lock if the caller requested access
1918 * to the lock
1920 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1921 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1922 if (lckp) {
1923 *lckp = lck;
1924 } else {
1925 talloc_free(lck);
1927 } else if (!NT_STATUS_IS_OK(status)) {
1928 talloc_free(lck);
1929 if (lckp) {
1930 *lckp = NULL;
1932 } else if (lckp) {
1933 *lckp = lck;
1936 return status;
1940 determine if the file size of a file can be changed,
1941 or if it is prevented by an already open file
1943 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1944 struct ntvfs_request *req,
1945 struct pvfs_filename *name,
1946 struct odb_lock **lckp)
1948 NTSTATUS status;
1949 DATA_BLOB key;
1950 struct odb_lock *lck;
1951 uint32_t share_access;
1952 uint32_t access_mask;
1953 bool break_to_none;
1954 bool delete_on_close;
1956 status = pvfs_locking_key(name, name, &key);
1957 if (!NT_STATUS_IS_OK(status)) {
1958 return NT_STATUS_NO_MEMORY;
1961 lck = odb_lock(req, pvfs->odb_context, &key);
1962 if (lck == NULL) {
1963 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1964 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1967 share_access = NTCREATEX_SHARE_ACCESS_READ |
1968 NTCREATEX_SHARE_ACCESS_WRITE |
1969 NTCREATEX_SHARE_ACCESS_DELETE;
1971 * this code previous set only SEC_FILE_WRITE_ATTRIBUTE, with
1972 * a comment that this seemed to be wrong, but matched windows
1973 * behaviour. It now appears that this windows behaviour is
1974 * just a bug.
1976 access_mask = SEC_FILE_WRITE_ATTRIBUTE | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
1977 delete_on_close = false;
1978 break_to_none = true;
1980 status = odb_can_open(lck, name->stream_id,
1981 share_access, access_mask, delete_on_close,
1982 NTCREATEX_DISP_OPEN, break_to_none);
1985 * if it's a sharing violation or we got no oplock
1986 * only keep the lock if the caller requested access
1987 * to the lock
1989 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1990 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1991 if (lckp) {
1992 *lckp = lck;
1993 } else {
1994 talloc_free(lck);
1996 } else if (!NT_STATUS_IS_OK(status)) {
1997 talloc_free(lck);
1998 if (lckp) {
1999 *lckp = NULL;
2001 } else if (lckp) {
2002 *lckp = lck;
2005 return status;
2009 determine if file meta data can be accessed, or if it is prevented by an
2010 already open file
2012 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
2013 struct ntvfs_request *req,
2014 struct pvfs_filename *name)
2016 NTSTATUS status;
2017 DATA_BLOB key;
2018 struct odb_lock *lck;
2019 uint32_t share_access;
2020 uint32_t access_mask;
2021 bool delete_on_close;
2023 status = pvfs_locking_key(name, name, &key);
2024 if (!NT_STATUS_IS_OK(status)) {
2025 return NT_STATUS_NO_MEMORY;
2028 lck = odb_lock(req, pvfs->odb_context, &key);
2029 if (lck == NULL) {
2030 DEBUG(0,("Unable to lock opendb for can_stat\n"));
2031 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2034 share_access = NTCREATEX_SHARE_ACCESS_READ |
2035 NTCREATEX_SHARE_ACCESS_WRITE;
2036 access_mask = SEC_FILE_READ_ATTRIBUTE;
2037 delete_on_close = false;
2039 status = odb_can_open(lck, name->stream_id,
2040 share_access, access_mask, delete_on_close,
2041 NTCREATEX_DISP_OPEN, false);
2043 if (!NT_STATUS_IS_OK(status)) {
2044 talloc_free(lck);
2047 return status;
2052 determine if delete on close is set on
2054 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
2056 NTSTATUS status;
2057 bool del_on_close;
2059 status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key,
2060 &del_on_close, NULL);
2061 if (!NT_STATUS_IS_OK(status)) {
2062 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2063 return false;
2066 return del_on_close;