smbd: Remove superfluous ()
[Samba.git] / source4 / ntvfs / posix / pvfs_open.c
blobceee64255f23f641517044745df5d05f8547e539
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, h->name->allow_override) != 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, name->allow_override) == -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, name->allow_override);
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, h->name->allow_override) != 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 = brlock_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, name->allow_override);
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 if (!NT_STATUS_IS_OK(status)) {
721 goto cleanup_delete;
725 /* form the lock context used for byte range locking and
726 opendb locking */
727 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
728 if (!NT_STATUS_IS_OK(status)) {
729 goto cleanup_delete;
732 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
733 if (!NT_STATUS_IS_OK(status)) {
734 goto cleanup_delete;
737 /* grab a lock on the open file record */
738 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
739 if (lck == NULL) {
740 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
741 name->full_name));
742 /* we were supposed to do a blocking lock, so something
743 is badly wrong! */
744 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
745 goto cleanup_delete;
748 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
749 del_on_close = true;
750 } else {
751 del_on_close = false;
754 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
755 oplock_level = OPLOCK_NONE;
756 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
757 oplock_level = OPLOCK_BATCH;
758 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
759 oplock_level = OPLOCK_EXCLUSIVE;
762 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
763 allow_level_II_oplock = true;
766 status = odb_can_open(lck, name->stream_id,
767 share_access, access_mask, del_on_close,
768 io->generic.in.open_disposition, false);
769 if (!NT_STATUS_IS_OK(status)) {
770 talloc_free(lck);
771 /* bad news, we must have hit a race - we don't delete the file
772 here as the most likely scenario is that someone else created
773 the file at the same time */
774 close(fd);
775 return status;
778 f->ntvfs = h;
779 f->pvfs = pvfs;
780 f->pending_list = NULL;
781 f->lock_count = 0;
782 f->share_access = io->generic.in.share_access;
783 f->access_mask = access_mask;
784 f->impersonation = io->generic.in.impersonation;
785 f->notify_buffer = NULL;
786 f->search = NULL;
788 f->handle->pvfs = pvfs;
789 f->handle->name = talloc_steal(f->handle, name);
790 f->handle->fd = fd;
791 f->handle->create_options = io->generic.in.create_options;
792 f->handle->private_flags = io->generic.in.private_flags;
793 f->handle->seek_offset = 0;
794 f->handle->position = 0;
795 f->handle->mode = 0;
796 f->handle->oplock = NULL;
797 f->handle->have_opendb_entry = true;
798 ZERO_STRUCT(f->handle->write_time);
799 f->handle->open_completed = false;
801 status = odb_open_file(lck, f->handle, name->full_name,
802 &f->handle->fd, name->dos.write_time,
803 allow_level_II_oplock,
804 oplock_level, &oplock_granted);
805 talloc_free(lck);
806 if (!NT_STATUS_IS_OK(status)) {
807 /* bad news, we must have hit a race - we don't delete the file
808 here as the most likely scenario is that someone else created
809 the file at the same time */
810 close(fd);
811 return status;
814 DLIST_ADD(pvfs->files.list, f);
816 /* setup a destructor to avoid file descriptor leaks on
817 abnormal termination */
818 talloc_set_destructor(f, pvfs_fnum_destructor);
819 talloc_set_destructor(f->handle, pvfs_handle_destructor);
821 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
822 oplock_granted = OPLOCK_BATCH;
823 } else if (oplock_granted != OPLOCK_NONE) {
824 status = pvfs_setup_oplock(f, oplock_granted);
825 if (!NT_STATUS_IS_OK(status)) {
826 return status;
830 io->generic.out.oplock_level = oplock_granted;
831 io->generic.out.file.ntvfs = f->ntvfs;
832 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
833 io->generic.out.create_time = name->dos.create_time;
834 io->generic.out.access_time = name->dos.access_time;
835 io->generic.out.write_time = name->dos.write_time;
836 io->generic.out.change_time = name->dos.change_time;
837 io->generic.out.attrib = name->dos.attrib;
838 io->generic.out.alloc_size = name->dos.alloc_size;
839 io->generic.out.size = name->st.st_size;
840 io->generic.out.file_type = FILE_TYPE_DISK;
841 io->generic.out.ipc_state = 0;
842 io->generic.out.is_directory = 0;
844 /* success - keep the file handle */
845 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
846 if (!NT_STATUS_IS_OK(status)) {
847 goto cleanup_delete;
850 f->handle->open_completed = true;
852 notify_trigger(pvfs->notify_context,
853 NOTIFY_ACTION_ADDED,
854 FILE_NOTIFY_CHANGE_FILE_NAME,
855 name->full_name);
857 return NT_STATUS_OK;
859 cleanup_delete:
860 close(fd);
861 pvfs_sys_unlink(pvfs, name->full_name, name->allow_override);
862 return status;
866 state of a pending retry
868 struct pvfs_odb_retry {
869 struct ntvfs_module_context *ntvfs;
870 struct ntvfs_request *req;
871 DATA_BLOB odb_locking_key;
872 void *io;
873 void *private_data;
874 void (*callback)(struct pvfs_odb_retry *r,
875 struct ntvfs_module_context *ntvfs,
876 struct ntvfs_request *req,
877 void *io,
878 void *private_data,
879 enum pvfs_wait_notice reason);
882 /* destroy a pending request */
883 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
885 struct pvfs_state *pvfs = talloc_get_type(r->ntvfs->private_data,
886 struct pvfs_state);
887 if (r->odb_locking_key.data) {
888 struct odb_lock *lck;
889 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
890 if (lck != NULL) {
891 odb_remove_pending(lck, r);
893 talloc_free(lck);
895 return 0;
898 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
900 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
902 if (reason == PVFS_WAIT_EVENT) {
904 * The pending odb entry is already removed.
905 * We use a null locking key to indicate this
906 * to the destructor.
908 data_blob_free(&r->odb_locking_key);
911 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
915 setup for a retry of a request that was rejected
916 by odb_can_open()
918 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
919 struct ntvfs_request *req,
920 struct odb_lock *lck,
921 struct timeval end_time,
922 void *io,
923 void *private_data,
924 void (*callback)(struct pvfs_odb_retry *r,
925 struct ntvfs_module_context *ntvfs,
926 struct ntvfs_request *req,
927 void *io,
928 void *private_data,
929 enum pvfs_wait_notice reason))
931 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
932 struct pvfs_state);
933 struct pvfs_odb_retry *r;
934 struct pvfs_wait *wait_handle;
935 NTSTATUS status;
937 r = talloc(req, struct pvfs_odb_retry);
938 NT_STATUS_HAVE_NO_MEMORY(r);
940 r->ntvfs = ntvfs;
941 r->req = req;
942 r->io = io;
943 r->private_data = private_data;
944 r->callback = callback;
945 r->odb_locking_key = odb_get_key(r, lck);
946 if (r->odb_locking_key.data == NULL) {
947 return NT_STATUS_NO_MEMORY;
950 /* setup a pending lock */
951 status = odb_open_file_pending(lck, r);
952 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
954 * maybe only a unix application
955 * has the file open
957 data_blob_free(&r->odb_locking_key);
958 } else if (!NT_STATUS_IS_OK(status)) {
959 return status;
962 talloc_free(lck);
964 talloc_set_destructor(r, pvfs_odb_retry_destructor);
966 wait_handle = pvfs_wait_message(pvfs, req,
967 MSG_PVFS_RETRY_OPEN, end_time,
968 pvfs_odb_retry_callback, r);
969 if (wait_handle == NULL) {
970 return NT_STATUS_NO_MEMORY;
973 talloc_steal(r, wait_handle);
975 return NT_STATUS_OK;
979 retry an open after a sharing violation
981 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
982 struct ntvfs_module_context *ntvfs,
983 struct ntvfs_request *req,
984 void *_io,
985 void *private_data,
986 enum pvfs_wait_notice reason)
988 union smb_open *io = talloc_get_type(_io, union smb_open);
989 struct timeval *final_timeout = NULL;
990 NTSTATUS status;
992 if (private_data) {
993 final_timeout = talloc_get_type(private_data,
994 struct timeval);
997 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
998 just a bug in their server, but we better do the same */
999 if (reason == PVFS_WAIT_CANCEL) {
1000 return;
1003 if (reason == PVFS_WAIT_TIMEOUT) {
1004 if (final_timeout &&
1005 !timeval_expired(final_timeout)) {
1007 * we need to retry periodictly
1008 * after an EAGAIN as there's
1009 * no way the kernel tell us
1010 * an oplock is released.
1012 goto retry;
1014 /* if it timed out, then give the failure
1015 immediately */
1016 talloc_free(r);
1017 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
1018 req->async_states->send_fn(req);
1019 return;
1022 retry:
1023 talloc_free(r);
1025 /* try the open again, which could trigger another retry setup
1026 if it wants to, so we have to unmark the async flag so we
1027 will know if it does a second async reply */
1028 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
1030 status = pvfs_open(ntvfs, req, io);
1031 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
1032 /* the 2nd try also replied async, so we don't send
1033 the reply yet */
1034 return;
1037 /* re-mark it async, just in case someone up the chain does
1038 paranoid checking */
1039 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1041 /* send the reply up the chain */
1042 req->async_states->status = status;
1043 req->async_states->send_fn(req);
1048 special handling for openx DENY_DOS semantics
1050 This function attempts a reference open using an existing handle. If its allowed,
1051 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
1052 open processing continues.
1054 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
1055 struct ntvfs_request *req, union smb_open *io,
1056 struct pvfs_file *f, struct odb_lock *lck)
1058 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1059 struct pvfs_state);
1060 struct pvfs_file *f2;
1061 struct pvfs_filename *name;
1062 NTSTATUS status;
1064 /* search for an existing open with the right parameters. Note
1065 the magic ntcreatex options flag, which is set in the
1066 generic mapping code. This might look ugly, but its
1067 actually pretty much now w2k does it internally as well.
1069 If you look at the BASE-DENYDOS test you will see that a
1070 DENY_DOS is a very special case, and in the right
1071 circumstances you actually get the _same_ handle back
1072 twice, rather than a new handle.
1074 for (f2=pvfs->files.list;f2;f2=f2->next) {
1075 if (f2 != f &&
1076 f2->ntvfs->session_info == req->session_info &&
1077 f2->ntvfs->smbpid == req->smbpid &&
1078 (f2->handle->private_flags &
1079 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
1080 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
1081 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1082 strcasecmp_m(f2->handle->name->original_name,
1083 io->generic.in.fname)==0) {
1084 break;
1088 if (!f2) {
1089 return NT_STATUS_SHARING_VIOLATION;
1092 /* quite an insane set of semantics ... */
1093 if (is_exe_filename(io->generic.in.fname) &&
1094 (f2->handle->private_flags & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1095 return NT_STATUS_SHARING_VIOLATION;
1099 setup a reference to the existing handle
1101 talloc_free(f->handle);
1102 f->handle = talloc_reference(f, f2->handle);
1104 talloc_free(lck);
1106 name = f->handle->name;
1108 io->generic.out.oplock_level = OPLOCK_NONE;
1109 io->generic.out.file.ntvfs = f->ntvfs;
1110 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1111 io->generic.out.create_time = name->dos.create_time;
1112 io->generic.out.access_time = name->dos.access_time;
1113 io->generic.out.write_time = name->dos.write_time;
1114 io->generic.out.change_time = name->dos.change_time;
1115 io->generic.out.attrib = name->dos.attrib;
1116 io->generic.out.alloc_size = name->dos.alloc_size;
1117 io->generic.out.size = name->st.st_size;
1118 io->generic.out.file_type = FILE_TYPE_DISK;
1119 io->generic.out.ipc_state = 0;
1120 io->generic.out.is_directory = 0;
1122 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1123 NT_STATUS_NOT_OK_RETURN(status);
1125 return NT_STATUS_OK;
1131 setup for a open retry after a sharing violation
1133 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1134 struct ntvfs_request *req,
1135 union smb_open *io,
1136 struct pvfs_file *f,
1137 struct odb_lock *lck,
1138 NTSTATUS parent_status)
1140 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1141 struct pvfs_state);
1142 NTSTATUS status;
1143 struct timeval end_time;
1144 struct timeval *final_timeout = NULL;
1146 if (io->generic.in.private_flags &
1147 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1148 /* see if we can satisfy the request using the special DENY_DOS
1149 code */
1150 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1151 if (NT_STATUS_IS_OK(status)) {
1152 return status;
1156 /* the retry should allocate a new file handle */
1157 talloc_free(f);
1159 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1160 end_time = timeval_add(&req->statistics.request_time,
1161 0, pvfs->sharing_violation_delay);
1162 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1163 end_time = timeval_add(&req->statistics.request_time,
1164 pvfs->oplock_break_timeout, 0);
1165 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1167 * we got EAGAIN which means a unix application
1168 * has an oplock or share mode
1170 * we retry every 4/5 of the sharing violation delay
1171 * to see if the unix application
1172 * has released the oplock or share mode.
1174 final_timeout = talloc(req, struct timeval);
1175 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1176 *final_timeout = timeval_add(&req->statistics.request_time,
1177 pvfs->oplock_break_timeout,
1179 end_time = timeval_current_ofs_usec((pvfs->sharing_violation_delay*4)/5);
1180 end_time = timeval_min(final_timeout, &end_time);
1181 } else {
1182 return NT_STATUS_INTERNAL_ERROR;
1185 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1186 final_timeout, pvfs_retry_open_sharing);
1190 open a file
1192 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1193 struct ntvfs_request *req, union smb_open *io)
1195 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1196 struct pvfs_state);
1197 int flags = 0;
1198 struct pvfs_filename *name;
1199 struct pvfs_file *f;
1200 struct ntvfs_handle *h;
1201 NTSTATUS status;
1202 int fd, count;
1203 struct odb_lock *lck;
1204 uint32_t create_options;
1205 uint32_t create_options_must_ignore_mask;
1206 uint32_t share_access;
1207 uint32_t access_mask;
1208 uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1209 bool del_on_close;
1210 bool stream_existed, stream_truncate=false;
1211 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1212 bool allow_level_II_oplock = false;
1214 /* use the generic mapping code to avoid implementing all the
1215 different open calls. */
1216 if (io->generic.level != RAW_OPEN_GENERIC &&
1217 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1218 return ntvfs_map_open(ntvfs, req, io);
1221 ZERO_STRUCT(io->generic.out);
1223 create_options = io->generic.in.create_options;
1224 share_access = io->generic.in.share_access;
1225 access_mask = io->generic.in.access_mask;
1227 if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1228 DEBUG(3,(__location__ ": Invalid share_access 0x%08x for %s\n",
1229 share_access, io->ntcreatex.in.fname));
1230 return NT_STATUS_INVALID_PARAMETER;
1234 * These options are ignored,
1235 * but we reuse some of them as private values for the generic mapping
1237 create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
1238 create_options &= ~create_options_must_ignore_mask;
1240 if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1241 DEBUG(2,(__location__ " create_options 0x%x not supported\n",
1242 create_options));
1243 return NT_STATUS_NOT_SUPPORTED;
1246 if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
1247 DEBUG(3,(__location__ ": Invalid create_options 0x%08x for %s\n",
1248 create_options, io->ntcreatex.in.fname));
1249 return NT_STATUS_INVALID_PARAMETER;
1252 /* TODO: When we implement HSM, add a hook here not to pull
1253 * the actual file off tape, when this option is passed from
1254 * the client */
1255 if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1256 /* no-op */
1259 /* TODO: If (unlikely) Linux does a good compressed
1260 * filesystem, we might need an ioctl call for this */
1261 if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
1262 /* no-op */
1265 if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
1266 create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
1269 /* Open the file with sync, if they asked for it, but
1270 'strict sync = no' turns this client request into a no-op */
1271 if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && !(pvfs->flags | PVFS_FLAG_STRICT_SYNC)) {
1272 flags |= O_SYNC;
1276 /* other create options are not allowed */
1277 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1278 !(access_mask & SEC_STD_DELETE)) {
1279 DEBUG(3,(__location__ ": Invalid delete_on_close option 0x%08x with access_mask 0x%08x for %s\n",
1280 create_options, access_mask, io->ntcreatex.in.fname));
1281 return NT_STATUS_INVALID_PARAMETER;
1284 if (access_mask & SEC_MASK_INVALID) {
1285 return NT_STATUS_ACCESS_DENIED;
1288 /* what does this bit really mean?? */
1289 if (req->ctx->protocol >= PROTOCOL_SMB2_02 &&
1290 access_mask == SEC_STD_SYNCHRONIZE) {
1291 return NT_STATUS_ACCESS_DENIED;
1294 /* cope with non-zero root_fid */
1295 if (io->ntcreatex.in.root_fid.ntvfs != NULL) {
1296 f = pvfs_find_fd(pvfs, req, io->ntcreatex.in.root_fid.ntvfs);
1297 if (f == NULL) {
1298 return NT_STATUS_INVALID_HANDLE;
1300 if (f->handle->fd != -1) {
1301 return NT_STATUS_INVALID_DEVICE_REQUEST;
1303 io->ntcreatex.in.fname = talloc_asprintf(req, "%s\\%s",
1304 f->handle->name->original_name,
1305 io->ntcreatex.in.fname);
1306 NT_STATUS_HAVE_NO_MEMORY(io->ntcreatex.in.fname);
1309 if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1310 FILE_ATTRIBUTE_VOLUME|
1311 (~FILE_ATTRIBUTE_ALL_MASK))) {
1312 DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
1313 io->ntcreatex.in.file_attr, io->ntcreatex.in.fname));
1314 return NT_STATUS_INVALID_PARAMETER;
1317 /* we ignore some file_attr bits */
1318 io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED |
1319 FILE_ATTRIBUTE_COMPRESSED |
1320 FILE_ATTRIBUTE_REPARSE_POINT |
1321 FILE_ATTRIBUTE_SPARSE |
1322 FILE_ATTRIBUTE_NORMAL);
1324 /* resolve the cifs name to a posix name */
1325 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1326 PVFS_RESOLVE_STREAMS, &name);
1327 if (!NT_STATUS_IS_OK(status)) {
1328 return status;
1331 /* if the client specified that it must not be a directory then
1332 check that it isn't */
1333 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1334 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1335 return NT_STATUS_FILE_IS_A_DIRECTORY;
1338 /* if the client specified that it must be a directory then
1339 check that it is */
1340 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1341 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1342 return NT_STATUS_NOT_A_DIRECTORY;
1345 /* directory opens are handled separately */
1346 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1347 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1348 return pvfs_open_directory(pvfs, req, name, io);
1351 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1352 open doesn't match */
1353 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1355 switch (io->generic.in.open_disposition) {
1356 case NTCREATEX_DISP_SUPERSEDE:
1357 case NTCREATEX_DISP_OVERWRITE_IF:
1358 if (name->stream_name == NULL) {
1359 flags = O_TRUNC;
1360 } else {
1361 stream_truncate = true;
1363 create_action = NTCREATEX_ACTION_TRUNCATED;
1364 break;
1366 case NTCREATEX_DISP_OPEN:
1367 if (!name->stream_exists) {
1368 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1370 flags = 0;
1371 break;
1373 case NTCREATEX_DISP_OVERWRITE:
1374 if (!name->stream_exists) {
1375 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1377 if (name->stream_name == NULL) {
1378 flags = O_TRUNC;
1379 } else {
1380 stream_truncate = true;
1382 create_action = NTCREATEX_ACTION_TRUNCATED;
1383 break;
1385 case NTCREATEX_DISP_CREATE:
1386 if (name->stream_exists) {
1387 return NT_STATUS_OBJECT_NAME_COLLISION;
1389 flags = 0;
1390 break;
1392 case NTCREATEX_DISP_OPEN_IF:
1393 flags = 0;
1394 break;
1396 default:
1397 DEBUG(3,(__location__ ": Invalid open disposition 0x%08x for %s\n",
1398 io->generic.in.open_disposition, name->original_name));
1399 return NT_STATUS_INVALID_PARAMETER;
1402 /* handle creating a new file separately */
1403 if (!name->exists) {
1404 status = pvfs_create_file(pvfs, req, name, io);
1405 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1406 return status;
1409 /* we've hit a race - the file was created during this call */
1410 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1411 return status;
1414 /* try re-resolving the name */
1415 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1416 if (!NT_STATUS_IS_OK(status)) {
1417 return status;
1419 /* fall through to a normal open */
1422 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1423 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1424 return NT_STATUS_CANNOT_DELETE;
1427 /* check the security descriptor */
1428 status = pvfs_access_check(pvfs, req, name, &access_mask);
1429 NT_STATUS_NOT_OK_RETURN(status);
1431 if (io->generic.in.query_maximal_access) {
1432 status = pvfs_access_maximal_allowed(pvfs, req, name,
1433 &io->generic.out.maximal_access);
1434 NT_STATUS_NOT_OK_RETURN(status);
1437 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1438 NT_STATUS_NOT_OK_RETURN(status);
1440 f = talloc(h, struct pvfs_file);
1441 if (f == NULL) {
1442 return NT_STATUS_NO_MEMORY;
1445 f->handle = talloc(f, struct pvfs_file_handle);
1446 if (f->handle == NULL) {
1447 return NT_STATUS_NO_MEMORY;
1450 f->ntvfs = h;
1451 f->pvfs = pvfs;
1452 f->pending_list = NULL;
1453 f->lock_count = 0;
1454 f->share_access = io->generic.in.share_access;
1455 f->access_mask = access_mask;
1456 f->impersonation = io->generic.in.impersonation;
1457 f->notify_buffer = NULL;
1458 f->search = NULL;
1460 f->handle->pvfs = pvfs;
1461 f->handle->fd = -1;
1462 f->handle->name = talloc_steal(f->handle, name);
1463 f->handle->create_options = io->generic.in.create_options;
1464 f->handle->private_flags = io->generic.in.private_flags;
1465 f->handle->seek_offset = 0;
1466 f->handle->position = 0;
1467 f->handle->mode = 0;
1468 f->handle->oplock = NULL;
1469 f->handle->have_opendb_entry = false;
1470 ZERO_STRUCT(f->handle->write_time);
1471 f->handle->open_completed = false;
1473 /* form the lock context used for byte range locking and
1474 opendb locking */
1475 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1476 if (!NT_STATUS_IS_OK(status)) {
1477 return status;
1480 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1481 if (!NT_STATUS_IS_OK(status)) {
1482 return status;
1485 /* get a lock on this file before the actual open */
1486 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1487 if (lck == NULL) {
1488 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1489 name->full_name));
1490 /* we were supposed to do a blocking lock, so something
1491 is badly wrong! */
1492 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1495 DLIST_ADD(pvfs->files.list, f);
1497 /* setup a destructor to avoid file descriptor leaks on
1498 abnormal termination */
1499 talloc_set_destructor(f, pvfs_fnum_destructor);
1500 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1503 * Only SMB2 takes care of the delete_on_close,
1504 * on existing files
1506 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1507 req->ctx->protocol >= PROTOCOL_SMB2_02) {
1508 del_on_close = true;
1509 } else {
1510 del_on_close = false;
1513 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1514 oplock_level = OPLOCK_NONE;
1515 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1516 oplock_level = OPLOCK_BATCH;
1517 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1518 oplock_level = OPLOCK_EXCLUSIVE;
1521 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1522 allow_level_II_oplock = true;
1525 /* see if we are allowed to open at the same time as existing opens */
1526 status = odb_can_open(lck, name->stream_id,
1527 share_access, access_mask, del_on_close,
1528 io->generic.in.open_disposition, false);
1531 * on a sharing violation we need to retry when the file is closed by
1532 * the other user, or after 1 second
1533 * on a non granted oplock we need to retry when the file is closed by
1534 * the other user, or after 30 seconds
1536 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1537 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1538 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1539 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1542 if (!NT_STATUS_IS_OK(status)) {
1543 talloc_free(lck);
1544 return status;
1547 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1548 flags |= O_RDWR;
1549 } else {
1550 flags |= O_RDONLY;
1553 /* do the actual open */
1554 fd = pvfs_sys_open(pvfs, f->handle->name->full_name, flags | O_NONBLOCK, 0, name->allow_override);
1555 if (fd == -1) {
1556 status = pvfs_map_errno(f->pvfs, errno);
1558 DEBUG(0,(__location__ " mapped errno %s for %s (was %d)\n",
1559 nt_errstr(status), f->handle->name->full_name, errno));
1561 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1563 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1564 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1565 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1568 talloc_free(lck);
1569 return status;
1572 f->handle->fd = fd;
1574 status = brlock_count(f->pvfs->brl_context, f->brl_handle, &count);
1575 if (!NT_STATUS_IS_OK(status)) {
1576 talloc_free(lck);
1577 return status;
1580 if (count != 0) {
1581 oplock_level = OPLOCK_NONE;
1584 /* now really mark the file as open */
1585 status = odb_open_file(lck, f->handle, name->full_name,
1586 &f->handle->fd, name->dos.write_time,
1587 allow_level_II_oplock,
1588 oplock_level, &oplock_granted);
1590 if (!NT_STATUS_IS_OK(status)) {
1591 talloc_free(lck);
1592 return status;
1595 f->handle->have_opendb_entry = true;
1597 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1598 oplock_granted = OPLOCK_BATCH;
1599 } else if (oplock_granted != OPLOCK_NONE) {
1600 status = pvfs_setup_oplock(f, oplock_granted);
1601 if (!NT_STATUS_IS_OK(status)) {
1602 talloc_free(lck);
1603 return status;
1607 stream_existed = name->stream_exists;
1609 /* if this was a stream create then create the stream as well */
1610 if (!name->stream_exists) {
1611 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1612 if (!NT_STATUS_IS_OK(status)) {
1613 talloc_free(lck);
1614 return status;
1616 if (stream_truncate) {
1617 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1618 if (!NT_STATUS_IS_OK(status)) {
1619 talloc_free(lck);
1620 return status;
1625 /* re-resolve the open fd */
1626 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1627 if (!NT_STATUS_IS_OK(status)) {
1628 talloc_free(lck);
1629 return status;
1632 if (f->handle->name->stream_id == 0 &&
1633 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1634 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1635 /* for overwrite we may need to replace file permissions */
1636 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1637 mode_t mode = pvfs_fileperms(pvfs, attrib);
1638 if (f->handle->name->st.st_mode != mode &&
1639 f->handle->name->dos.attrib != attrib &&
1640 pvfs_sys_fchmod(pvfs, fd, mode, name->allow_override) == -1) {
1641 talloc_free(lck);
1642 return pvfs_map_errno(pvfs, errno);
1644 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1645 name->dos.attrib = attrib;
1646 status = pvfs_dosattrib_save(pvfs, name, fd);
1647 if (!NT_STATUS_IS_OK(status)) {
1648 talloc_free(lck);
1649 return status;
1653 talloc_free(lck);
1655 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1656 NT_STATUS_NOT_OK_RETURN(status);
1658 /* mark the open as having completed fully, so delete on close
1659 can now be used */
1660 f->handle->open_completed = true;
1662 io->generic.out.oplock_level = oplock_granted;
1663 io->generic.out.file.ntvfs = h;
1664 io->generic.out.create_action = stream_existed?
1665 create_action:NTCREATEX_ACTION_CREATED;
1667 io->generic.out.create_time = name->dos.create_time;
1668 io->generic.out.access_time = name->dos.access_time;
1669 io->generic.out.write_time = name->dos.write_time;
1670 io->generic.out.change_time = name->dos.change_time;
1671 io->generic.out.attrib = name->dos.attrib;
1672 io->generic.out.alloc_size = name->dos.alloc_size;
1673 io->generic.out.size = name->st.st_size;
1674 io->generic.out.file_type = FILE_TYPE_DISK;
1675 io->generic.out.ipc_state = 0;
1676 io->generic.out.is_directory = 0;
1678 return NT_STATUS_OK;
1683 close a file
1685 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1686 struct ntvfs_request *req, union smb_close *io)
1688 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1689 struct pvfs_state);
1690 struct pvfs_file *f;
1692 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1693 return NT_STATUS_DOS(ERRSRV, ERRerror);
1696 if (io->generic.level != RAW_CLOSE_GENERIC) {
1697 return ntvfs_map_close(ntvfs, req, io);
1700 f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1701 if (!f) {
1702 return NT_STATUS_INVALID_HANDLE;
1705 if (!null_time(io->generic.in.write_time)) {
1706 f->handle->write_time.update_forced = false;
1707 f->handle->write_time.update_on_close = true;
1708 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1711 if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1712 struct pvfs_filename *name;
1713 NTSTATUS status;
1714 struct pvfs_file_handle *h = f->handle;
1716 status = pvfs_resolve_name_handle(pvfs, h);
1717 if (!NT_STATUS_IS_OK(status)) {
1718 return status;
1720 name = h->name;
1722 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1723 io->generic.out.create_time = name->dos.create_time;
1724 io->generic.out.access_time = name->dos.access_time;
1725 io->generic.out.write_time = name->dos.write_time;
1726 io->generic.out.change_time = name->dos.change_time;
1727 io->generic.out.alloc_size = name->dos.alloc_size;
1728 io->generic.out.size = name->st.st_size;
1729 io->generic.out.file_attr = name->dos.attrib;
1730 } else {
1731 ZERO_STRUCT(io->generic.out);
1734 talloc_free(f);
1736 return NT_STATUS_OK;
1741 logoff - close all file descriptors open by a vuid
1743 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1744 struct ntvfs_request *req)
1746 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1747 struct pvfs_state);
1748 struct pvfs_file *f, *next;
1750 /* If pvfs is NULL, we never logged on, and no files are open. */
1751 if(pvfs == NULL) {
1752 return NT_STATUS_OK;
1755 for (f=pvfs->files.list;f;f=next) {
1756 next = f->next;
1757 if (f->ntvfs->session_info == req->session_info) {
1758 talloc_free(f);
1762 return NT_STATUS_OK;
1767 exit - close files for the current pid
1769 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1770 struct ntvfs_request *req)
1772 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1773 struct pvfs_state);
1774 struct pvfs_file *f, *next;
1776 for (f=pvfs->files.list;f;f=next) {
1777 next = f->next;
1778 if (f->ntvfs->session_info == req->session_info &&
1779 f->ntvfs->smbpid == req->smbpid) {
1780 talloc_free(f);
1784 return NT_STATUS_OK;
1789 change the delete on close flag on an already open file
1791 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1792 struct ntvfs_request *req,
1793 struct pvfs_file *f, bool del_on_close)
1795 struct odb_lock *lck;
1796 NTSTATUS status;
1798 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1799 return NT_STATUS_CANNOT_DELETE;
1802 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1803 !pvfs_directory_empty(pvfs, f->handle->name)) {
1804 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1807 if (del_on_close) {
1808 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1809 } else {
1810 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1813 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1814 if (lck == NULL) {
1815 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1818 status = odb_set_delete_on_close(lck, del_on_close);
1820 talloc_free(lck);
1822 return status;
1827 determine if a file can be deleted, or if it is prevented by an
1828 already open file
1830 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1831 struct ntvfs_request *req,
1832 struct pvfs_filename *name,
1833 struct odb_lock **lckp)
1835 NTSTATUS status;
1836 DATA_BLOB key;
1837 struct odb_lock *lck;
1838 uint32_t share_access;
1839 uint32_t access_mask;
1840 bool delete_on_close;
1842 status = pvfs_locking_key(name, name, &key);
1843 if (!NT_STATUS_IS_OK(status)) {
1844 return NT_STATUS_NO_MEMORY;
1847 lck = odb_lock(req, pvfs->odb_context, &key);
1848 if (lck == NULL) {
1849 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1850 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1853 share_access = NTCREATEX_SHARE_ACCESS_READ |
1854 NTCREATEX_SHARE_ACCESS_WRITE |
1855 NTCREATEX_SHARE_ACCESS_DELETE;
1856 access_mask = SEC_STD_DELETE;
1857 delete_on_close = true;
1859 status = odb_can_open(lck, name->stream_id,
1860 share_access, access_mask, delete_on_close,
1861 NTCREATEX_DISP_OPEN, false);
1863 if (NT_STATUS_IS_OK(status)) {
1864 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1868 * if it's a sharing violation or we got no oplock
1869 * only keep the lock if the caller requested access
1870 * to the lock
1872 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1873 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1874 if (lckp) {
1875 *lckp = lck;
1876 } else {
1877 talloc_free(lck);
1879 } else if (!NT_STATUS_IS_OK(status)) {
1880 talloc_free(lck);
1881 if (lckp) {
1882 *lckp = NULL;
1884 } else if (lckp) {
1885 *lckp = lck;
1888 return status;
1892 determine if a file can be renamed, or if it is prevented by an
1893 already open file
1895 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1896 struct ntvfs_request *req,
1897 struct pvfs_filename *name,
1898 struct odb_lock **lckp)
1900 NTSTATUS status;
1901 DATA_BLOB key;
1902 struct odb_lock *lck;
1903 uint32_t share_access;
1904 uint32_t access_mask;
1905 bool delete_on_close;
1907 status = pvfs_locking_key(name, name, &key);
1908 if (!NT_STATUS_IS_OK(status)) {
1909 return NT_STATUS_NO_MEMORY;
1912 lck = odb_lock(req, pvfs->odb_context, &key);
1913 if (lck == NULL) {
1914 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1915 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1918 share_access = NTCREATEX_SHARE_ACCESS_READ |
1919 NTCREATEX_SHARE_ACCESS_WRITE;
1920 access_mask = SEC_STD_DELETE;
1921 delete_on_close = false;
1923 status = odb_can_open(lck, name->stream_id,
1924 share_access, access_mask, delete_on_close,
1925 NTCREATEX_DISP_OPEN, false);
1928 * if it's a sharing violation or we got no oplock
1929 * only keep the lock if the caller requested access
1930 * to the lock
1932 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1933 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1934 if (lckp) {
1935 *lckp = lck;
1936 } else {
1937 talloc_free(lck);
1939 } else if (!NT_STATUS_IS_OK(status)) {
1940 talloc_free(lck);
1941 if (lckp) {
1942 *lckp = NULL;
1944 } else if (lckp) {
1945 *lckp = lck;
1948 return status;
1952 determine if the file size of a file can be changed,
1953 or if it is prevented by an already open file
1955 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1956 struct ntvfs_request *req,
1957 struct pvfs_filename *name,
1958 struct odb_lock **lckp)
1960 NTSTATUS status;
1961 DATA_BLOB key;
1962 struct odb_lock *lck;
1963 uint32_t share_access;
1964 uint32_t access_mask;
1965 bool break_to_none;
1966 bool delete_on_close;
1968 status = pvfs_locking_key(name, name, &key);
1969 if (!NT_STATUS_IS_OK(status)) {
1970 return NT_STATUS_NO_MEMORY;
1973 lck = odb_lock(req, pvfs->odb_context, &key);
1974 if (lck == NULL) {
1975 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1976 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1979 share_access = NTCREATEX_SHARE_ACCESS_READ |
1980 NTCREATEX_SHARE_ACCESS_WRITE |
1981 NTCREATEX_SHARE_ACCESS_DELETE;
1983 * this code previous set only SEC_FILE_WRITE_ATTRIBUTE, with
1984 * a comment that this seemed to be wrong, but matched windows
1985 * behaviour. It now appears that this windows behaviour is
1986 * just a bug.
1988 access_mask = SEC_FILE_WRITE_ATTRIBUTE | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
1989 delete_on_close = false;
1990 break_to_none = true;
1992 status = odb_can_open(lck, name->stream_id,
1993 share_access, access_mask, delete_on_close,
1994 NTCREATEX_DISP_OPEN, break_to_none);
1997 * if it's a sharing violation or we got no oplock
1998 * only keep the lock if the caller requested access
1999 * to the lock
2001 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
2002 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
2003 if (lckp) {
2004 *lckp = lck;
2005 } else {
2006 talloc_free(lck);
2008 } else if (!NT_STATUS_IS_OK(status)) {
2009 talloc_free(lck);
2010 if (lckp) {
2011 *lckp = NULL;
2013 } else if (lckp) {
2014 *lckp = lck;
2017 return status;
2021 determine if file meta data can be accessed, or if it is prevented by an
2022 already open file
2024 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
2025 struct ntvfs_request *req,
2026 struct pvfs_filename *name)
2028 NTSTATUS status;
2029 DATA_BLOB key;
2030 struct odb_lock *lck;
2031 uint32_t share_access;
2032 uint32_t access_mask;
2033 bool delete_on_close;
2035 status = pvfs_locking_key(name, name, &key);
2036 if (!NT_STATUS_IS_OK(status)) {
2037 return NT_STATUS_NO_MEMORY;
2040 lck = odb_lock(req, pvfs->odb_context, &key);
2041 if (lck == NULL) {
2042 DEBUG(0,("Unable to lock opendb for can_stat\n"));
2043 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2046 share_access = NTCREATEX_SHARE_ACCESS_READ |
2047 NTCREATEX_SHARE_ACCESS_WRITE;
2048 access_mask = SEC_FILE_READ_ATTRIBUTE;
2049 delete_on_close = false;
2051 status = odb_can_open(lck, name->stream_id,
2052 share_access, access_mask, delete_on_close,
2053 NTCREATEX_DISP_OPEN, false);
2055 if (!NT_STATUS_IS_OK(status)) {
2056 talloc_free(lck);
2059 return status;
2064 determine if delete on close is set on
2066 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
2068 NTSTATUS status;
2069 bool del_on_close;
2071 status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key,
2072 &del_on_close, NULL);
2073 if (!NT_STATUS_IS_OK(status)) {
2074 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2075 return false;
2078 return del_on_close;