s3:torture:delete: fix a comment
[Samba/gebeck_regimport.git] / source4 / ntvfs / posix / pvfs_open.c
bloba095f746331adca236e69caae9d1d8afe06d471e
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 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, name->allow_override);
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_usec((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, count;
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_02 &&
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_02) {
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, name->allow_override);
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 status = brlock_count(f->pvfs->brl_context, f->brl_handle, &count);
1573 if (!NT_STATUS_IS_OK(status)) {
1574 talloc_free(lck);
1575 return status;
1578 if (count != 0) {
1579 oplock_level = OPLOCK_NONE;
1582 /* now really mark the file as open */
1583 status = odb_open_file(lck, f->handle, name->full_name,
1584 &f->handle->fd, name->dos.write_time,
1585 allow_level_II_oplock,
1586 oplock_level, &oplock_granted);
1588 if (!NT_STATUS_IS_OK(status)) {
1589 talloc_free(lck);
1590 return status;
1593 f->handle->have_opendb_entry = true;
1595 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1596 oplock_granted = OPLOCK_BATCH;
1597 } else if (oplock_granted != OPLOCK_NONE) {
1598 status = pvfs_setup_oplock(f, oplock_granted);
1599 if (!NT_STATUS_IS_OK(status)) {
1600 talloc_free(lck);
1601 return status;
1605 stream_existed = name->stream_exists;
1607 /* if this was a stream create then create the stream as well */
1608 if (!name->stream_exists) {
1609 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1610 if (!NT_STATUS_IS_OK(status)) {
1611 talloc_free(lck);
1612 return status;
1614 if (stream_truncate) {
1615 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1616 if (!NT_STATUS_IS_OK(status)) {
1617 talloc_free(lck);
1618 return status;
1623 /* re-resolve the open fd */
1624 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1625 if (!NT_STATUS_IS_OK(status)) {
1626 talloc_free(lck);
1627 return status;
1630 if (f->handle->name->stream_id == 0 &&
1631 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1632 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1633 /* for overwrite we may need to replace file permissions */
1634 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1635 mode_t mode = pvfs_fileperms(pvfs, attrib);
1636 if (f->handle->name->st.st_mode != mode &&
1637 f->handle->name->dos.attrib != attrib &&
1638 pvfs_sys_fchmod(pvfs, fd, mode, name->allow_override) == -1) {
1639 talloc_free(lck);
1640 return pvfs_map_errno(pvfs, errno);
1642 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1643 name->dos.attrib = attrib;
1644 status = pvfs_dosattrib_save(pvfs, name, fd);
1645 if (!NT_STATUS_IS_OK(status)) {
1646 talloc_free(lck);
1647 return status;
1651 talloc_free(lck);
1653 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1654 NT_STATUS_NOT_OK_RETURN(status);
1656 /* mark the open as having completed fully, so delete on close
1657 can now be used */
1658 f->handle->open_completed = true;
1660 io->generic.out.oplock_level = oplock_granted;
1661 io->generic.out.file.ntvfs = h;
1662 io->generic.out.create_action = stream_existed?
1663 create_action:NTCREATEX_ACTION_CREATED;
1665 io->generic.out.create_time = name->dos.create_time;
1666 io->generic.out.access_time = name->dos.access_time;
1667 io->generic.out.write_time = name->dos.write_time;
1668 io->generic.out.change_time = name->dos.change_time;
1669 io->generic.out.attrib = name->dos.attrib;
1670 io->generic.out.alloc_size = name->dos.alloc_size;
1671 io->generic.out.size = name->st.st_size;
1672 io->generic.out.file_type = FILE_TYPE_DISK;
1673 io->generic.out.ipc_state = 0;
1674 io->generic.out.is_directory = 0;
1676 return NT_STATUS_OK;
1681 close a file
1683 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1684 struct ntvfs_request *req, union smb_close *io)
1686 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1687 struct pvfs_state);
1688 struct pvfs_file *f;
1690 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1691 return NT_STATUS_DOS(ERRSRV, ERRerror);
1694 if (io->generic.level != RAW_CLOSE_GENERIC) {
1695 return ntvfs_map_close(ntvfs, req, io);
1698 f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1699 if (!f) {
1700 return NT_STATUS_INVALID_HANDLE;
1703 if (!null_time(io->generic.in.write_time)) {
1704 f->handle->write_time.update_forced = false;
1705 f->handle->write_time.update_on_close = true;
1706 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1709 if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1710 struct pvfs_filename *name;
1711 NTSTATUS status;
1712 struct pvfs_file_handle *h = f->handle;
1714 status = pvfs_resolve_name_handle(pvfs, h);
1715 if (!NT_STATUS_IS_OK(status)) {
1716 return status;
1718 name = h->name;
1720 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1721 io->generic.out.create_time = name->dos.create_time;
1722 io->generic.out.access_time = name->dos.access_time;
1723 io->generic.out.write_time = name->dos.write_time;
1724 io->generic.out.change_time = name->dos.change_time;
1725 io->generic.out.alloc_size = name->dos.alloc_size;
1726 io->generic.out.size = name->st.st_size;
1727 io->generic.out.file_attr = name->dos.attrib;
1728 } else {
1729 ZERO_STRUCT(io->generic.out);
1732 talloc_free(f);
1734 return NT_STATUS_OK;
1739 logoff - close all file descriptors open by a vuid
1741 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1742 struct ntvfs_request *req)
1744 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1745 struct pvfs_state);
1746 struct pvfs_file *f, *next;
1748 /* If pvfs is NULL, we never logged on, and no files are open. */
1749 if(pvfs == NULL) {
1750 return NT_STATUS_OK;
1753 for (f=pvfs->files.list;f;f=next) {
1754 next = f->next;
1755 if (f->ntvfs->session_info == req->session_info) {
1756 talloc_free(f);
1760 return NT_STATUS_OK;
1765 exit - close files for the current pid
1767 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1768 struct ntvfs_request *req)
1770 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1771 struct pvfs_state);
1772 struct pvfs_file *f, *next;
1774 for (f=pvfs->files.list;f;f=next) {
1775 next = f->next;
1776 if (f->ntvfs->session_info == req->session_info &&
1777 f->ntvfs->smbpid == req->smbpid) {
1778 talloc_free(f);
1782 return NT_STATUS_OK;
1787 change the delete on close flag on an already open file
1789 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1790 struct ntvfs_request *req,
1791 struct pvfs_file *f, bool del_on_close)
1793 struct odb_lock *lck;
1794 NTSTATUS status;
1796 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1797 return NT_STATUS_CANNOT_DELETE;
1800 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1801 !pvfs_directory_empty(pvfs, f->handle->name)) {
1802 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1805 if (del_on_close) {
1806 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1807 } else {
1808 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1811 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1812 if (lck == NULL) {
1813 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1816 status = odb_set_delete_on_close(lck, del_on_close);
1818 talloc_free(lck);
1820 return status;
1825 determine if a file can be deleted, or if it is prevented by an
1826 already open file
1828 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1829 struct ntvfs_request *req,
1830 struct pvfs_filename *name,
1831 struct odb_lock **lckp)
1833 NTSTATUS status;
1834 DATA_BLOB key;
1835 struct odb_lock *lck;
1836 uint32_t share_access;
1837 uint32_t access_mask;
1838 bool delete_on_close;
1840 status = pvfs_locking_key(name, name, &key);
1841 if (!NT_STATUS_IS_OK(status)) {
1842 return NT_STATUS_NO_MEMORY;
1845 lck = odb_lock(req, pvfs->odb_context, &key);
1846 if (lck == NULL) {
1847 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1848 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1851 share_access = NTCREATEX_SHARE_ACCESS_READ |
1852 NTCREATEX_SHARE_ACCESS_WRITE |
1853 NTCREATEX_SHARE_ACCESS_DELETE;
1854 access_mask = SEC_STD_DELETE;
1855 delete_on_close = true;
1857 status = odb_can_open(lck, name->stream_id,
1858 share_access, access_mask, delete_on_close,
1859 NTCREATEX_DISP_OPEN, false);
1861 if (NT_STATUS_IS_OK(status)) {
1862 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1866 * if it's a sharing violation or we got no oplock
1867 * only keep the lock if the caller requested access
1868 * to the lock
1870 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1871 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1872 if (lckp) {
1873 *lckp = lck;
1874 } else {
1875 talloc_free(lck);
1877 } else if (!NT_STATUS_IS_OK(status)) {
1878 talloc_free(lck);
1879 if (lckp) {
1880 *lckp = NULL;
1882 } else if (lckp) {
1883 *lckp = lck;
1886 return status;
1890 determine if a file can be renamed, or if it is prevented by an
1891 already open file
1893 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1894 struct ntvfs_request *req,
1895 struct pvfs_filename *name,
1896 struct odb_lock **lckp)
1898 NTSTATUS status;
1899 DATA_BLOB key;
1900 struct odb_lock *lck;
1901 uint32_t share_access;
1902 uint32_t access_mask;
1903 bool delete_on_close;
1905 status = pvfs_locking_key(name, name, &key);
1906 if (!NT_STATUS_IS_OK(status)) {
1907 return NT_STATUS_NO_MEMORY;
1910 lck = odb_lock(req, pvfs->odb_context, &key);
1911 if (lck == NULL) {
1912 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1913 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1916 share_access = NTCREATEX_SHARE_ACCESS_READ |
1917 NTCREATEX_SHARE_ACCESS_WRITE;
1918 access_mask = SEC_STD_DELETE;
1919 delete_on_close = false;
1921 status = odb_can_open(lck, name->stream_id,
1922 share_access, access_mask, delete_on_close,
1923 NTCREATEX_DISP_OPEN, false);
1926 * if it's a sharing violation or we got no oplock
1927 * only keep the lock if the caller requested access
1928 * to the lock
1930 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1931 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1932 if (lckp) {
1933 *lckp = lck;
1934 } else {
1935 talloc_free(lck);
1937 } else if (!NT_STATUS_IS_OK(status)) {
1938 talloc_free(lck);
1939 if (lckp) {
1940 *lckp = NULL;
1942 } else if (lckp) {
1943 *lckp = lck;
1946 return status;
1950 determine if the file size of a file can be changed,
1951 or if it is prevented by an already open file
1953 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1954 struct ntvfs_request *req,
1955 struct pvfs_filename *name,
1956 struct odb_lock **lckp)
1958 NTSTATUS status;
1959 DATA_BLOB key;
1960 struct odb_lock *lck;
1961 uint32_t share_access;
1962 uint32_t access_mask;
1963 bool break_to_none;
1964 bool delete_on_close;
1966 status = pvfs_locking_key(name, name, &key);
1967 if (!NT_STATUS_IS_OK(status)) {
1968 return NT_STATUS_NO_MEMORY;
1971 lck = odb_lock(req, pvfs->odb_context, &key);
1972 if (lck == NULL) {
1973 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1974 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1977 share_access = NTCREATEX_SHARE_ACCESS_READ |
1978 NTCREATEX_SHARE_ACCESS_WRITE |
1979 NTCREATEX_SHARE_ACCESS_DELETE;
1981 * this code previous set only SEC_FILE_WRITE_ATTRIBUTE, with
1982 * a comment that this seemed to be wrong, but matched windows
1983 * behaviour. It now appears that this windows behaviour is
1984 * just a bug.
1986 access_mask = SEC_FILE_WRITE_ATTRIBUTE | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
1987 delete_on_close = false;
1988 break_to_none = true;
1990 status = odb_can_open(lck, name->stream_id,
1991 share_access, access_mask, delete_on_close,
1992 NTCREATEX_DISP_OPEN, break_to_none);
1995 * if it's a sharing violation or we got no oplock
1996 * only keep the lock if the caller requested access
1997 * to the lock
1999 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
2000 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
2001 if (lckp) {
2002 *lckp = lck;
2003 } else {
2004 talloc_free(lck);
2006 } else if (!NT_STATUS_IS_OK(status)) {
2007 talloc_free(lck);
2008 if (lckp) {
2009 *lckp = NULL;
2011 } else if (lckp) {
2012 *lckp = lck;
2015 return status;
2019 determine if file meta data can be accessed, or if it is prevented by an
2020 already open file
2022 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
2023 struct ntvfs_request *req,
2024 struct pvfs_filename *name)
2026 NTSTATUS status;
2027 DATA_BLOB key;
2028 struct odb_lock *lck;
2029 uint32_t share_access;
2030 uint32_t access_mask;
2031 bool delete_on_close;
2033 status = pvfs_locking_key(name, name, &key);
2034 if (!NT_STATUS_IS_OK(status)) {
2035 return NT_STATUS_NO_MEMORY;
2038 lck = odb_lock(req, pvfs->odb_context, &key);
2039 if (lck == NULL) {
2040 DEBUG(0,("Unable to lock opendb for can_stat\n"));
2041 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2044 share_access = NTCREATEX_SHARE_ACCESS_READ |
2045 NTCREATEX_SHARE_ACCESS_WRITE;
2046 access_mask = SEC_FILE_READ_ATTRIBUTE;
2047 delete_on_close = false;
2049 status = odb_can_open(lck, name->stream_id,
2050 share_access, access_mask, delete_on_close,
2051 NTCREATEX_DISP_OPEN, false);
2053 if (!NT_STATUS_IS_OK(status)) {
2054 talloc_free(lck);
2057 return status;
2062 determine if delete on close is set on
2064 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
2066 NTSTATUS status;
2067 bool del_on_close;
2069 status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key,
2070 &del_on_close, NULL);
2071 if (!NT_STATUS_IS_OK(status)) {
2072 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2073 return false;
2076 return del_on_close;