librpc/ndr: Fix fuzz CI on latest tumbleweed
[Samba.git] / source4 / ntvfs / posix / pvfs_open.c
blob860861d8c21de7106a9e31f6497bd08818662b3e
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 if (io->generic.in.query_on_disk_id) {
411 ZERO_ARRAY(io->generic.out.on_disk_id);
412 SBVAL(io->generic.out.on_disk_id, 0, name->st.st_ino);
413 SBVAL(io->generic.out.on_disk_id, 8, name->st.st_dev);
416 /* the open succeeded, keep this handle permanently */
417 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
418 if (!NT_STATUS_IS_OK(status)) {
419 goto cleanup_delete;
422 f->handle->open_completed = true;
424 io->generic.out.oplock_level = OPLOCK_NONE;
425 io->generic.out.file.ntvfs = h;
426 io->generic.out.create_action = create_action;
427 io->generic.out.create_time = name->dos.create_time;
428 io->generic.out.access_time = name->dos.access_time;
429 io->generic.out.write_time = name->dos.write_time;
430 io->generic.out.change_time = name->dos.change_time;
431 io->generic.out.attrib = name->dos.attrib;
432 io->generic.out.alloc_size = name->dos.alloc_size;
433 io->generic.out.size = name->st.st_size;
434 io->generic.out.file_type = FILE_TYPE_DISK;
435 io->generic.out.ipc_state = 0;
436 io->generic.out.is_directory = 1;
438 return NT_STATUS_OK;
440 cleanup_delete:
441 pvfs_sys_rmdir(pvfs, name->full_name, name->allow_override);
442 return status;
446 destroy a struct pvfs_file_handle
448 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
450 talloc_free(h->write_time.update_event);
451 h->write_time.update_event = NULL;
453 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
454 h->name->stream_name) {
455 NTSTATUS status;
456 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
457 if (!NT_STATUS_IS_OK(status)) {
458 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
459 h->name->stream_name, h->name->full_name));
463 if (h->fd != -1) {
464 if (close(h->fd) != 0) {
465 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
466 h->fd, h->name->full_name, strerror(errno)));
468 h->fd = -1;
471 if (!h->write_time.update_forced &&
472 h->write_time.update_on_close &&
473 h->write_time.close_time == 0) {
474 struct timeval tv;
475 tv = timeval_current();
476 h->write_time.close_time = timeval_to_nttime(&tv);
479 if (h->have_opendb_entry) {
480 struct odb_lock *lck;
481 NTSTATUS status;
482 const char *delete_path = NULL;
484 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
485 if (lck == NULL) {
486 DEBUG(0,("Unable to lock opendb for close\n"));
487 return 0;
490 if (h->write_time.update_forced) {
491 status = odb_get_file_infos(h->pvfs->odb_context,
492 &h->odb_locking_key,
493 NULL,
494 &h->write_time.close_time);
495 if (!NT_STATUS_IS_OK(status)) {
496 DEBUG(0,("Unable get write time for '%s' - %s\n",
497 h->name->full_name, nt_errstr(status)));
500 h->write_time.update_forced = false;
501 h->write_time.update_on_close = true;
502 } else if (h->write_time.update_on_close) {
503 status = odb_set_write_time(lck, h->write_time.close_time, true);
504 if (!NT_STATUS_IS_OK(status)) {
505 DEBUG(0,("Unable set write time for '%s' - %s\n",
506 h->name->full_name, nt_errstr(status)));
510 status = odb_close_file(lck, h, &delete_path);
511 if (!NT_STATUS_IS_OK(status)) {
512 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
513 h->name->full_name, nt_errstr(status)));
516 if (h->name->stream_name == NULL &&
517 h->open_completed && delete_path) {
518 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
519 if (!NT_STATUS_IS_OK(status)) {
520 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
521 delete_path, nt_errstr(status)));
523 if (pvfs_sys_unlink(h->pvfs, delete_path, h->name->allow_override) != 0) {
524 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
525 delete_path, strerror(errno)));
526 } else {
527 notify_trigger(h->pvfs->notify_context,
528 NOTIFY_ACTION_REMOVED,
529 FILE_NOTIFY_CHANGE_FILE_NAME,
530 delete_path);
532 h->write_time.update_on_close = false;
535 talloc_free(lck);
538 if (h->write_time.update_on_close) {
539 struct timeval tv[2];
541 nttime_to_timeval(&tv[0], h->name->dos.access_time);
542 nttime_to_timeval(&tv[1], h->write_time.close_time);
544 if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
545 if (utimes(h->name->full_name, tv) == -1) {
546 DEBUG(3,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
547 h->name->full_name, strerror(errno)));
552 return 0;
557 destroy a struct pvfs_file
559 static int pvfs_fnum_destructor(struct pvfs_file *f)
561 DLIST_REMOVE(f->pvfs->files.list, f);
562 pvfs_lock_close(f->pvfs, f);
563 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
565 return 0;
570 form the lock context used for byte range locking. This is separate
571 from the locking key used for opendb locking as it needs to take
572 account of file streams (each stream is a separate byte range
573 locking space)
575 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
576 struct pvfs_filename *name,
577 struct ntvfs_handle *ntvfs,
578 struct brl_handle **_h)
580 DATA_BLOB odb_key, key;
581 NTSTATUS status;
582 struct brl_handle *h;
584 status = pvfs_locking_key(name, mem_ctx, &odb_key);
585 NT_STATUS_NOT_OK_RETURN(status);
587 if (name->stream_name == NULL) {
588 key = odb_key;
589 } else {
590 key = data_blob_talloc(mem_ctx, NULL,
591 odb_key.length + strlen(name->stream_name) + 1);
592 NT_STATUS_HAVE_NO_MEMORY(key.data);
593 memcpy(key.data, odb_key.data, odb_key.length);
594 memcpy(key.data + odb_key.length,
595 name->stream_name, strlen(name->stream_name) + 1);
596 data_blob_free(&odb_key);
599 h = brlock_create_handle(mem_ctx, ntvfs, &key);
600 NT_STATUS_HAVE_NO_MEMORY(h);
602 *_h = h;
603 return NT_STATUS_OK;
607 create a new file
609 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
610 struct ntvfs_request *req,
611 struct pvfs_filename *name,
612 union smb_open *io)
614 struct pvfs_file *f;
615 NTSTATUS status;
616 struct ntvfs_handle *h;
617 int flags, fd;
618 struct odb_lock *lck;
619 uint32_t create_options = io->generic.in.create_options;
620 uint32_t share_access = io->generic.in.share_access;
621 uint32_t access_mask = io->generic.in.access_mask;
622 mode_t mode;
623 uint32_t attrib;
624 bool del_on_close;
625 struct pvfs_filename *parent;
626 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
627 bool allow_level_II_oplock = false;
628 struct security_descriptor *sd = NULL;
630 if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
631 DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
632 io->ntcreatex.in.file_attr, name->original_name));
633 return NT_STATUS_INVALID_PARAMETER;
636 if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
637 DEBUG(3,(__location__ ": Invalid encryption request for %s\n",
638 name->original_name));
639 return NT_STATUS_ACCESS_DENIED;
642 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
643 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
644 DEBUG(4,(__location__ ": Invalid delete on close for readonly file %s\n",
645 name->original_name));
646 return NT_STATUS_CANNOT_DELETE;
649 sd = io->ntcreatex.in.sec_desc;
650 status = pvfs_access_check_create(pvfs, req, name, &access_mask, false, &sd);
651 NT_STATUS_NOT_OK_RETURN(status);
653 /* check that the parent isn't opened with delete on close set */
654 status = pvfs_resolve_parent(pvfs, req, name, &parent);
655 if (NT_STATUS_IS_OK(status)) {
656 DATA_BLOB locking_key;
657 status = pvfs_locking_key(parent, req, &locking_key);
658 NT_STATUS_NOT_OK_RETURN(status);
659 status = odb_get_file_infos(pvfs->odb_context, &locking_key,
660 &del_on_close, NULL);
661 NT_STATUS_NOT_OK_RETURN(status);
662 if (del_on_close) {
663 return NT_STATUS_DELETE_PENDING;
667 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
668 flags = O_RDWR;
669 } else {
670 flags = O_RDONLY;
673 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
674 NT_STATUS_NOT_OK_RETURN(status);
676 f = talloc(h, struct pvfs_file);
677 NT_STATUS_HAVE_NO_MEMORY(f);
679 f->handle = talloc(f, struct pvfs_file_handle);
680 NT_STATUS_HAVE_NO_MEMORY(f->handle);
682 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
683 mode = pvfs_fileperms(pvfs, attrib);
685 /* create the file */
686 fd = pvfs_sys_open(pvfs, name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode, name->allow_override);
687 if (fd == -1) {
688 return pvfs_map_errno(pvfs, errno);
691 pvfs_xattr_unlink_hook(pvfs, name->full_name);
693 /* if this was a stream create then create the stream as well */
694 if (name->stream_name) {
695 status = pvfs_stream_create(pvfs, name, fd);
696 if (!NT_STATUS_IS_OK(status)) {
697 close(fd);
698 return status;
702 /* re-resolve the open fd */
703 status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
704 if (!NT_STATUS_IS_OK(status)) {
705 close(fd);
706 return status;
709 /* support initial alloc sizes */
710 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
711 name->dos.attrib = attrib;
712 status = pvfs_dosattrib_save(pvfs, name, fd);
713 if (!NT_STATUS_IS_OK(status)) {
714 goto cleanup_delete;
718 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io, sd);
719 if (!NT_STATUS_IS_OK(status)) {
720 goto cleanup_delete;
723 if (io->generic.in.query_maximal_access) {
724 status = pvfs_access_maximal_allowed(pvfs, req, name,
725 &io->generic.out.maximal_access);
726 if (!NT_STATUS_IS_OK(status)) {
727 goto cleanup_delete;
731 if (io->generic.in.query_on_disk_id) {
732 ZERO_ARRAY(io->generic.out.on_disk_id);
733 SBVAL(io->generic.out.on_disk_id, 0, name->st.st_ino);
734 SBVAL(io->generic.out.on_disk_id, 8, name->st.st_dev);
737 /* form the lock context used for byte range locking and
738 opendb locking */
739 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
740 if (!NT_STATUS_IS_OK(status)) {
741 goto cleanup_delete;
744 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
745 if (!NT_STATUS_IS_OK(status)) {
746 goto cleanup_delete;
749 /* grab a lock on the open file record */
750 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
751 if (lck == NULL) {
752 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
753 name->full_name));
754 /* we were supposed to do a blocking lock, so something
755 is badly wrong! */
756 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
757 goto cleanup_delete;
760 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
761 del_on_close = true;
762 } else {
763 del_on_close = false;
766 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
767 oplock_level = OPLOCK_NONE;
768 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
769 oplock_level = OPLOCK_BATCH;
770 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
771 oplock_level = OPLOCK_EXCLUSIVE;
774 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
775 allow_level_II_oplock = true;
778 status = odb_can_open(lck, name->stream_id,
779 share_access, access_mask, del_on_close,
780 io->generic.in.open_disposition, false);
781 if (!NT_STATUS_IS_OK(status)) {
782 talloc_free(lck);
783 /* bad news, we must have hit a race - we don't delete the file
784 here as the most likely scenario is that someone else created
785 the file at the same time */
786 close(fd);
787 return status;
790 f->ntvfs = h;
791 f->pvfs = pvfs;
792 f->pending_list = NULL;
793 f->lock_count = 0;
794 f->share_access = io->generic.in.share_access;
795 f->access_mask = access_mask;
796 f->impersonation = io->generic.in.impersonation;
797 f->notify_buffer = NULL;
798 f->search = NULL;
800 f->handle->pvfs = pvfs;
801 f->handle->name = talloc_steal(f->handle, name);
802 f->handle->fd = fd;
803 f->handle->create_options = io->generic.in.create_options;
804 f->handle->private_flags = io->generic.in.private_flags;
805 f->handle->seek_offset = 0;
806 f->handle->position = 0;
807 f->handle->mode = 0;
808 f->handle->oplock = NULL;
809 f->handle->have_opendb_entry = true;
810 ZERO_STRUCT(f->handle->write_time);
811 f->handle->open_completed = false;
813 status = odb_open_file(lck, f->handle, name->full_name,
814 &f->handle->fd, name->dos.write_time,
815 allow_level_II_oplock,
816 oplock_level, &oplock_granted);
817 talloc_free(lck);
818 if (!NT_STATUS_IS_OK(status)) {
819 /* bad news, we must have hit a race - we don't delete the file
820 here as the most likely scenario is that someone else created
821 the file at the same time */
822 close(fd);
823 return status;
826 DLIST_ADD(pvfs->files.list, f);
828 /* setup a destructor to avoid file descriptor leaks on
829 abnormal termination */
830 talloc_set_destructor(f, pvfs_fnum_destructor);
831 talloc_set_destructor(f->handle, pvfs_handle_destructor);
833 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
834 oplock_granted = OPLOCK_BATCH;
835 } else if (oplock_granted != OPLOCK_NONE) {
836 status = pvfs_setup_oplock(f, oplock_granted);
837 if (!NT_STATUS_IS_OK(status)) {
838 return status;
842 io->generic.out.oplock_level = oplock_granted;
843 io->generic.out.file.ntvfs = f->ntvfs;
844 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
845 io->generic.out.create_time = name->dos.create_time;
846 io->generic.out.access_time = name->dos.access_time;
847 io->generic.out.write_time = name->dos.write_time;
848 io->generic.out.change_time = name->dos.change_time;
849 io->generic.out.attrib = name->dos.attrib;
850 io->generic.out.alloc_size = name->dos.alloc_size;
851 io->generic.out.size = name->st.st_size;
852 io->generic.out.file_type = FILE_TYPE_DISK;
853 io->generic.out.ipc_state = 0;
854 io->generic.out.is_directory = 0;
856 /* success - keep the file handle */
857 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
858 if (!NT_STATUS_IS_OK(status)) {
859 goto cleanup_delete;
862 f->handle->open_completed = true;
864 notify_trigger(pvfs->notify_context,
865 NOTIFY_ACTION_ADDED,
866 FILE_NOTIFY_CHANGE_FILE_NAME,
867 name->full_name);
869 return NT_STATUS_OK;
871 cleanup_delete:
872 close(fd);
873 pvfs_sys_unlink(pvfs, name->full_name, name->allow_override);
874 return status;
878 state of a pending retry
880 struct pvfs_odb_retry {
881 struct ntvfs_module_context *ntvfs;
882 struct ntvfs_request *req;
883 DATA_BLOB odb_locking_key;
884 void *io;
885 void *private_data;
886 void (*callback)(struct pvfs_odb_retry *r,
887 struct ntvfs_module_context *ntvfs,
888 struct ntvfs_request *req,
889 void *io,
890 void *private_data,
891 enum pvfs_wait_notice reason);
894 /* destroy a pending request */
895 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
897 struct pvfs_state *pvfs = talloc_get_type(r->ntvfs->private_data,
898 struct pvfs_state);
899 if (r->odb_locking_key.data) {
900 struct odb_lock *lck;
901 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
902 if (lck != NULL) {
903 odb_remove_pending(lck, r);
905 talloc_free(lck);
907 return 0;
910 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
912 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
914 if (reason == PVFS_WAIT_EVENT) {
916 * The pending odb entry is already removed.
917 * We use a null locking key to indicate this
918 * to the destructor.
920 data_blob_free(&r->odb_locking_key);
923 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
927 setup for a retry of a request that was rejected
928 by odb_can_open()
930 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
931 struct ntvfs_request *req,
932 struct odb_lock *lck,
933 struct timeval end_time,
934 void *io,
935 void *private_data,
936 void (*callback)(struct pvfs_odb_retry *r,
937 struct ntvfs_module_context *ntvfs,
938 struct ntvfs_request *req,
939 void *io,
940 void *private_data,
941 enum pvfs_wait_notice reason))
943 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
944 struct pvfs_state);
945 struct pvfs_odb_retry *r;
946 struct pvfs_wait *wait_handle;
947 NTSTATUS status;
949 r = talloc(req, struct pvfs_odb_retry);
950 NT_STATUS_HAVE_NO_MEMORY(r);
952 r->ntvfs = ntvfs;
953 r->req = req;
954 r->io = io;
955 r->private_data = private_data;
956 r->callback = callback;
957 r->odb_locking_key = odb_get_key(r, lck);
958 if (r->odb_locking_key.data == NULL) {
959 return NT_STATUS_NO_MEMORY;
962 /* setup a pending lock */
963 status = odb_open_file_pending(lck, r);
964 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
966 * maybe only a unix application
967 * has the file open
969 data_blob_free(&r->odb_locking_key);
970 } else if (!NT_STATUS_IS_OK(status)) {
971 return status;
974 talloc_free(lck);
976 talloc_set_destructor(r, pvfs_odb_retry_destructor);
978 wait_handle = pvfs_wait_message(pvfs, req,
979 MSG_PVFS_RETRY_OPEN, end_time,
980 pvfs_odb_retry_callback, r);
981 if (wait_handle == NULL) {
982 return NT_STATUS_NO_MEMORY;
985 talloc_steal(r, wait_handle);
987 return NT_STATUS_OK;
991 retry an open after a sharing violation
993 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
994 struct ntvfs_module_context *ntvfs,
995 struct ntvfs_request *req,
996 void *_io,
997 void *private_data,
998 enum pvfs_wait_notice reason)
1000 union smb_open *io = talloc_get_type(_io, union smb_open);
1001 struct timeval *final_timeout = NULL;
1002 NTSTATUS status;
1004 if (private_data) {
1005 final_timeout = talloc_get_type(private_data,
1006 struct timeval);
1009 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
1010 just a bug in their server, but we better do the same */
1011 if (reason == PVFS_WAIT_CANCEL) {
1012 return;
1015 if (reason == PVFS_WAIT_TIMEOUT) {
1016 if (final_timeout &&
1017 !timeval_expired(final_timeout)) {
1019 * we need to retry periodictly
1020 * after an EAGAIN as there's
1021 * no way the kernel tell us
1022 * an oplock is released.
1024 goto retry;
1026 /* if it timed out, then give the failure
1027 immediately */
1028 talloc_free(r);
1029 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
1030 req->async_states->send_fn(req);
1031 return;
1034 retry:
1035 talloc_free(r);
1037 /* try the open again, which could trigger another retry setup
1038 if it wants to, so we have to unmark the async flag so we
1039 will know if it does a second async reply */
1040 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
1042 status = pvfs_open(ntvfs, req, io);
1043 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
1044 /* the 2nd try also replied async, so we don't send
1045 the reply yet */
1046 return;
1049 /* re-mark it async, just in case someone up the chain does
1050 paranoid checking */
1051 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
1053 /* send the reply up the chain */
1054 req->async_states->status = status;
1055 req->async_states->send_fn(req);
1060 special handling for openx DENY_DOS semantics
1062 This function attempts a reference open using an existing handle. If its allowed,
1063 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
1064 open processing continues.
1066 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
1067 struct ntvfs_request *req, union smb_open *io,
1068 struct pvfs_file *f, struct odb_lock *lck)
1070 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1071 struct pvfs_state);
1072 struct pvfs_file *f2;
1073 struct pvfs_filename *name;
1074 NTSTATUS status;
1076 /* search for an existing open with the right parameters. Note
1077 the magic ntcreatex options flag, which is set in the
1078 generic mapping code. This might look ugly, but its
1079 actually pretty much now w2k does it internally as well.
1081 If you look at the BASE-DENYDOS test you will see that a
1082 DENY_DOS is a very special case, and in the right
1083 circumstances you actually get the _same_ handle back
1084 twice, rather than a new handle.
1086 for (f2=pvfs->files.list;f2;f2=f2->next) {
1087 if (f2 != f &&
1088 f2->ntvfs->session_info == req->session_info &&
1089 f2->ntvfs->smbpid == req->smbpid &&
1090 (f2->handle->private_flags &
1091 (NTCREATEX_FLAG_DENY_DOS |
1092 NTCREATEX_FLAG_DENY_FCB)) &&
1093 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1094 strcasecmp_m(f2->handle->name->original_name,
1095 io->generic.in.fname)==0) {
1096 break;
1100 if (!f2) {
1101 return NT_STATUS_SHARING_VIOLATION;
1104 /* quite an insane set of semantics ... */
1105 if (is_exe_filename(io->generic.in.fname) &&
1106 (f2->handle->private_flags & NTCREATEX_FLAG_DENY_DOS)) {
1107 return NT_STATUS_SHARING_VIOLATION;
1111 setup a reference to the existing handle
1113 talloc_free(f->handle);
1114 f->handle = talloc_reference(f, f2->handle);
1116 talloc_free(lck);
1118 name = f->handle->name;
1120 io->generic.out.oplock_level = OPLOCK_NONE;
1121 io->generic.out.file.ntvfs = f->ntvfs;
1122 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1123 io->generic.out.create_time = name->dos.create_time;
1124 io->generic.out.access_time = name->dos.access_time;
1125 io->generic.out.write_time = name->dos.write_time;
1126 io->generic.out.change_time = name->dos.change_time;
1127 io->generic.out.attrib = name->dos.attrib;
1128 io->generic.out.alloc_size = name->dos.alloc_size;
1129 io->generic.out.size = name->st.st_size;
1130 io->generic.out.file_type = FILE_TYPE_DISK;
1131 io->generic.out.ipc_state = 0;
1132 io->generic.out.is_directory = 0;
1134 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1135 NT_STATUS_NOT_OK_RETURN(status);
1137 return NT_STATUS_OK;
1143 setup for a open retry after a sharing violation
1145 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1146 struct ntvfs_request *req,
1147 union smb_open *io,
1148 struct pvfs_file *f,
1149 struct odb_lock *lck,
1150 NTSTATUS parent_status)
1152 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1153 struct pvfs_state);
1154 NTSTATUS status;
1155 struct timeval end_time;
1156 struct timeval *final_timeout = NULL;
1158 if (io->generic.in.private_flags &
1159 (NTCREATEX_FLAG_DENY_DOS | NTCREATEX_FLAG_DENY_FCB)) {
1160 /* see if we can satisfy the request using the special DENY_DOS
1161 code */
1162 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1163 if (NT_STATUS_IS_OK(status)) {
1164 return status;
1168 /* the retry should allocate a new file handle */
1169 talloc_free(f);
1171 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1172 end_time = timeval_add(&req->statistics.request_time,
1173 0, pvfs->sharing_violation_delay);
1174 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1175 end_time = timeval_add(&req->statistics.request_time,
1176 pvfs->oplock_break_timeout, 0);
1177 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1179 * we got EAGAIN which means a unix application
1180 * has an oplock or share mode
1182 * we retry every 4/5 of the sharing violation delay
1183 * to see if the unix application
1184 * has released the oplock or share mode.
1186 final_timeout = talloc(req, struct timeval);
1187 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1188 *final_timeout = timeval_add(&req->statistics.request_time,
1189 pvfs->oplock_break_timeout,
1191 end_time = timeval_current_ofs_usec((pvfs->sharing_violation_delay*4)/5);
1192 end_time = timeval_min(final_timeout, &end_time);
1193 } else {
1194 return NT_STATUS_INTERNAL_ERROR;
1197 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1198 final_timeout, pvfs_retry_open_sharing);
1202 open a file
1204 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1205 struct ntvfs_request *req, union smb_open *io)
1207 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1208 struct pvfs_state);
1209 int flags = 0;
1210 struct pvfs_filename *name;
1211 struct pvfs_file *f;
1212 struct ntvfs_handle *h;
1213 NTSTATUS status;
1214 int fd, count;
1215 struct odb_lock *lck;
1216 uint32_t create_options;
1217 uint32_t create_options_must_ignore_mask;
1218 uint32_t share_access;
1219 uint32_t access_mask;
1220 uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1221 bool del_on_close;
1222 bool stream_existed, stream_truncate=false;
1223 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1224 bool allow_level_II_oplock = false;
1226 /* use the generic mapping code to avoid implementing all the
1227 different open calls. */
1228 if (io->generic.level != RAW_OPEN_GENERIC &&
1229 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1230 return ntvfs_map_open(ntvfs, req, io);
1233 ZERO_STRUCT(io->generic.out);
1235 create_options = io->generic.in.create_options;
1236 share_access = io->generic.in.share_access;
1237 access_mask = io->generic.in.access_mask;
1239 if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1240 DEBUG(3,(__location__ ": Invalid share_access 0x%08x for %s\n",
1241 share_access, io->ntcreatex.in.fname));
1242 return NT_STATUS_INVALID_PARAMETER;
1246 * These options are ignored,
1247 * but we reuse some of them as private values for the generic mapping
1249 create_options_must_ignore_mask = NTCREATEX_OPTIONS_MUST_IGNORE_MASK;
1250 create_options &= ~create_options_must_ignore_mask;
1252 if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1253 DEBUG(2,(__location__ " create_options 0x%x not supported\n",
1254 create_options));
1255 return NT_STATUS_NOT_SUPPORTED;
1258 if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
1259 DEBUG(3,(__location__ ": Invalid create_options 0x%08x for %s\n",
1260 create_options, io->ntcreatex.in.fname));
1261 return NT_STATUS_INVALID_PARAMETER;
1264 /* TODO: When we implement HSM, add a hook here not to pull
1265 * the actual file off tape, when this option is passed from
1266 * the client */
1267 if (create_options & NTCREATEX_OPTIONS_NO_RECALL) {
1268 /* no-op */
1271 /* TODO: If (unlikely) Linux does a good compressed
1272 * filesystem, we might need an ioctl call for this */
1273 if (create_options & NTCREATEX_OPTIONS_NO_COMPRESSION) {
1274 /* no-op */
1277 if (create_options & NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING) {
1278 create_options |= NTCREATEX_OPTIONS_WRITE_THROUGH;
1281 /* Open the file with sync, if they asked for it, but
1282 'strict sync = no' turns this client request into a no-op */
1283 if (create_options & (NTCREATEX_OPTIONS_WRITE_THROUGH) && pvfs->flags & PVFS_FLAG_STRICT_SYNC) {
1284 flags |= O_SYNC;
1288 /* other create options are not allowed */
1289 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1290 !(access_mask & SEC_STD_DELETE)) {
1291 DEBUG(3,(__location__ ": Invalid delete_on_close option 0x%08x with access_mask 0x%08x for %s\n",
1292 create_options, access_mask, io->ntcreatex.in.fname));
1293 return NT_STATUS_INVALID_PARAMETER;
1296 if (access_mask & SEC_MASK_INVALID) {
1297 return NT_STATUS_ACCESS_DENIED;
1300 /* what does this bit really mean?? */
1301 if (req->ctx->protocol >= PROTOCOL_SMB2_02 &&
1302 access_mask == SEC_STD_SYNCHRONIZE) {
1303 return NT_STATUS_ACCESS_DENIED;
1306 /* cope with non-zero root_fid */
1307 if (io->ntcreatex.in.root_fid.ntvfs != NULL) {
1308 f = pvfs_find_fd(pvfs, req, io->ntcreatex.in.root_fid.ntvfs);
1309 if (f == NULL) {
1310 return NT_STATUS_INVALID_HANDLE;
1312 if (f->handle->fd != -1) {
1313 return NT_STATUS_INVALID_DEVICE_REQUEST;
1315 io->ntcreatex.in.fname = talloc_asprintf(req, "%s\\%s",
1316 f->handle->name->original_name,
1317 io->ntcreatex.in.fname);
1318 NT_STATUS_HAVE_NO_MEMORY(io->ntcreatex.in.fname);
1321 if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1322 FILE_ATTRIBUTE_VOLUME|
1323 (~FILE_ATTRIBUTE_ALL_MASK))) {
1324 DEBUG(3,(__location__ ": Invalid file_attr 0x%08x for %s\n",
1325 io->ntcreatex.in.file_attr, io->ntcreatex.in.fname));
1326 return NT_STATUS_INVALID_PARAMETER;
1329 /* we ignore some file_attr bits */
1330 io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED |
1331 FILE_ATTRIBUTE_COMPRESSED |
1332 FILE_ATTRIBUTE_REPARSE_POINT |
1333 FILE_ATTRIBUTE_SPARSE |
1334 FILE_ATTRIBUTE_NORMAL);
1336 /* resolve the cifs name to a posix name */
1337 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1338 PVFS_RESOLVE_STREAMS, &name);
1339 if (!NT_STATUS_IS_OK(status)) {
1340 return status;
1343 /* if the client specified that it must not be a directory then
1344 check that it isn't */
1345 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1346 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1347 return NT_STATUS_FILE_IS_A_DIRECTORY;
1350 /* if the client specified that it must be a directory then
1351 check that it is */
1352 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1353 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1354 return NT_STATUS_NOT_A_DIRECTORY;
1357 /* directory opens are handled separately */
1358 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1359 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1360 return pvfs_open_directory(pvfs, req, name, io);
1363 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1364 open doesn't match */
1365 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1367 switch (io->generic.in.open_disposition) {
1368 case NTCREATEX_DISP_SUPERSEDE:
1369 case NTCREATEX_DISP_OVERWRITE_IF:
1370 if (name->stream_name == NULL) {
1371 flags |= O_TRUNC;
1372 } else {
1373 stream_truncate = true;
1375 create_action = NTCREATEX_ACTION_TRUNCATED;
1376 break;
1378 case NTCREATEX_DISP_OPEN:
1379 if (!name->stream_exists) {
1380 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1382 break;
1384 case NTCREATEX_DISP_OVERWRITE:
1385 if (!name->stream_exists) {
1386 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1388 if (name->stream_name == NULL) {
1389 flags |= O_TRUNC;
1390 } else {
1391 stream_truncate = true;
1393 create_action = NTCREATEX_ACTION_TRUNCATED;
1394 break;
1396 case NTCREATEX_DISP_CREATE:
1397 if (name->stream_exists) {
1398 return NT_STATUS_OBJECT_NAME_COLLISION;
1400 break;
1402 case NTCREATEX_DISP_OPEN_IF:
1403 break;
1405 default:
1406 DEBUG(3,(__location__ ": Invalid open disposition 0x%08x for %s\n",
1407 io->generic.in.open_disposition, name->original_name));
1408 return NT_STATUS_INVALID_PARAMETER;
1411 /* handle creating a new file separately */
1412 if (!name->exists) {
1413 status = pvfs_create_file(pvfs, req, name, io);
1414 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1415 return status;
1418 /* we've hit a race - the file was created during this call */
1419 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1420 return status;
1423 /* try re-resolving the name */
1424 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1425 if (!NT_STATUS_IS_OK(status)) {
1426 return status;
1428 /* fall through to a normal open */
1431 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1432 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1433 return NT_STATUS_CANNOT_DELETE;
1436 /* check the security descriptor */
1437 status = pvfs_access_check(pvfs, req, name, &access_mask);
1438 NT_STATUS_NOT_OK_RETURN(status);
1440 if (io->generic.in.query_maximal_access) {
1441 status = pvfs_access_maximal_allowed(pvfs, req, name,
1442 &io->generic.out.maximal_access);
1443 NT_STATUS_NOT_OK_RETURN(status);
1446 if (io->generic.in.query_on_disk_id) {
1447 ZERO_ARRAY(io->generic.out.on_disk_id);
1448 SBVAL(io->generic.out.on_disk_id, 0, name->st.st_ino);
1449 SBVAL(io->generic.out.on_disk_id, 8, name->st.st_dev);
1452 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1453 NT_STATUS_NOT_OK_RETURN(status);
1455 f = talloc(h, struct pvfs_file);
1456 if (f == NULL) {
1457 return NT_STATUS_NO_MEMORY;
1460 f->handle = talloc(f, struct pvfs_file_handle);
1461 if (f->handle == NULL) {
1462 return NT_STATUS_NO_MEMORY;
1465 f->ntvfs = h;
1466 f->pvfs = pvfs;
1467 f->pending_list = NULL;
1468 f->lock_count = 0;
1469 f->share_access = io->generic.in.share_access;
1470 f->access_mask = access_mask;
1471 f->impersonation = io->generic.in.impersonation;
1472 f->notify_buffer = NULL;
1473 f->search = NULL;
1475 f->handle->pvfs = pvfs;
1476 f->handle->fd = -1;
1477 f->handle->name = talloc_steal(f->handle, name);
1478 f->handle->create_options = io->generic.in.create_options;
1479 f->handle->private_flags = io->generic.in.private_flags;
1480 f->handle->seek_offset = 0;
1481 f->handle->position = 0;
1482 f->handle->mode = 0;
1483 f->handle->oplock = NULL;
1484 f->handle->have_opendb_entry = false;
1485 ZERO_STRUCT(f->handle->write_time);
1486 f->handle->open_completed = false;
1488 /* form the lock context used for byte range locking and
1489 opendb locking */
1490 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1491 if (!NT_STATUS_IS_OK(status)) {
1492 return status;
1495 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1496 if (!NT_STATUS_IS_OK(status)) {
1497 return status;
1500 /* get a lock on this file before the actual open */
1501 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1502 if (lck == NULL) {
1503 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1504 name->full_name));
1505 /* we were supposed to do a blocking lock, so something
1506 is badly wrong! */
1507 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1510 DLIST_ADD(pvfs->files.list, f);
1512 /* setup a destructor to avoid file descriptor leaks on
1513 abnormal termination */
1514 talloc_set_destructor(f, pvfs_fnum_destructor);
1515 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1518 * Only SMB2 takes care of the delete_on_close,
1519 * on existing files
1521 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1522 req->ctx->protocol >= PROTOCOL_SMB2_02) {
1523 del_on_close = true;
1524 } else {
1525 del_on_close = false;
1528 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1529 oplock_level = OPLOCK_NONE;
1530 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1531 oplock_level = OPLOCK_BATCH;
1532 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1533 oplock_level = OPLOCK_EXCLUSIVE;
1536 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1537 allow_level_II_oplock = true;
1540 /* see if we are allowed to open at the same time as existing opens */
1541 status = odb_can_open(lck, name->stream_id,
1542 share_access, access_mask, del_on_close,
1543 io->generic.in.open_disposition, false);
1546 * on a sharing violation we need to retry when the file is closed by
1547 * the other user, or after 1 second
1548 * on a non granted oplock we need to retry when the file is closed by
1549 * the other user, or after 30 seconds
1551 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1552 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1553 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1554 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1557 if (!NT_STATUS_IS_OK(status)) {
1558 talloc_free(lck);
1559 return status;
1562 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1563 flags |= O_RDWR;
1564 } else {
1565 flags |= O_RDONLY;
1568 /* do the actual open */
1569 fd = pvfs_sys_open(pvfs, f->handle->name->full_name, flags | O_NONBLOCK, 0, name->allow_override);
1570 if (fd == -1) {
1571 status = pvfs_map_errno(f->pvfs, errno);
1573 DEBUG(0,(__location__ " mapped errno %s for %s (was %d)\n",
1574 nt_errstr(status), f->handle->name->full_name, errno));
1576 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1578 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1579 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1580 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1583 talloc_free(lck);
1584 return status;
1587 f->handle->fd = fd;
1589 status = brlock_count(f->pvfs->brl_context, f->brl_handle, &count);
1590 if (!NT_STATUS_IS_OK(status)) {
1591 talloc_free(lck);
1592 return status;
1595 if (count != 0) {
1596 oplock_level = OPLOCK_NONE;
1599 /* now really mark the file as open */
1600 status = odb_open_file(lck, f->handle, name->full_name,
1601 &f->handle->fd, name->dos.write_time,
1602 allow_level_II_oplock,
1603 oplock_level, &oplock_granted);
1605 if (!NT_STATUS_IS_OK(status)) {
1606 talloc_free(lck);
1607 return status;
1610 f->handle->have_opendb_entry = true;
1612 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1613 oplock_granted = OPLOCK_BATCH;
1614 } else if (oplock_granted != OPLOCK_NONE) {
1615 status = pvfs_setup_oplock(f, oplock_granted);
1616 if (!NT_STATUS_IS_OK(status)) {
1617 talloc_free(lck);
1618 return status;
1622 stream_existed = name->stream_exists;
1624 /* if this was a stream create then create the stream as well */
1625 if (!name->stream_exists) {
1626 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1627 if (!NT_STATUS_IS_OK(status)) {
1628 talloc_free(lck);
1629 return status;
1631 if (stream_truncate) {
1632 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1633 if (!NT_STATUS_IS_OK(status)) {
1634 talloc_free(lck);
1635 return status;
1640 /* re-resolve the open fd */
1641 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1642 if (!NT_STATUS_IS_OK(status)) {
1643 talloc_free(lck);
1644 return status;
1647 if (f->handle->name->stream_id == 0 &&
1648 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1649 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1650 /* for overwrite we may need to replace file permissions */
1651 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1652 mode_t mode = pvfs_fileperms(pvfs, attrib);
1653 if (f->handle->name->st.st_mode != mode &&
1654 f->handle->name->dos.attrib != attrib &&
1655 pvfs_sys_fchmod(pvfs, fd, mode, name->allow_override) == -1) {
1656 talloc_free(lck);
1657 return pvfs_map_errno(pvfs, errno);
1659 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1660 name->dos.attrib = attrib;
1661 status = pvfs_dosattrib_save(pvfs, name, fd);
1662 if (!NT_STATUS_IS_OK(status)) {
1663 talloc_free(lck);
1664 return status;
1668 talloc_free(lck);
1670 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1671 NT_STATUS_NOT_OK_RETURN(status);
1673 /* mark the open as having completed fully, so delete on close
1674 can now be used */
1675 f->handle->open_completed = true;
1677 io->generic.out.oplock_level = oplock_granted;
1678 io->generic.out.file.ntvfs = h;
1679 io->generic.out.create_action = stream_existed?
1680 create_action:NTCREATEX_ACTION_CREATED;
1682 io->generic.out.create_time = name->dos.create_time;
1683 io->generic.out.access_time = name->dos.access_time;
1684 io->generic.out.write_time = name->dos.write_time;
1685 io->generic.out.change_time = name->dos.change_time;
1686 io->generic.out.attrib = name->dos.attrib;
1687 io->generic.out.alloc_size = name->dos.alloc_size;
1688 io->generic.out.size = name->st.st_size;
1689 io->generic.out.file_type = FILE_TYPE_DISK;
1690 io->generic.out.ipc_state = 0;
1691 io->generic.out.is_directory = 0;
1693 return NT_STATUS_OK;
1698 close a file
1700 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1701 struct ntvfs_request *req, union smb_close *io)
1703 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1704 struct pvfs_state);
1705 struct pvfs_file *f;
1707 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1708 return NT_STATUS_DOS(ERRSRV, ERRerror);
1711 if (io->generic.level != RAW_CLOSE_GENERIC) {
1712 return ntvfs_map_close(ntvfs, req, io);
1715 f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1716 if (!f) {
1717 return NT_STATUS_INVALID_HANDLE;
1720 if (!null_time(io->generic.in.write_time)) {
1721 f->handle->write_time.update_forced = false;
1722 f->handle->write_time.update_on_close = true;
1723 unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
1726 if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1727 struct pvfs_filename *name;
1728 NTSTATUS status;
1729 struct pvfs_file_handle *h = f->handle;
1731 status = pvfs_resolve_name_handle(pvfs, h);
1732 if (!NT_STATUS_IS_OK(status)) {
1733 return status;
1735 name = h->name;
1737 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1738 io->generic.out.create_time = name->dos.create_time;
1739 io->generic.out.access_time = name->dos.access_time;
1740 io->generic.out.write_time = name->dos.write_time;
1741 io->generic.out.change_time = name->dos.change_time;
1742 io->generic.out.alloc_size = name->dos.alloc_size;
1743 io->generic.out.size = name->st.st_size;
1744 io->generic.out.file_attr = name->dos.attrib;
1745 } else {
1746 ZERO_STRUCT(io->generic.out);
1749 talloc_free(f);
1751 return NT_STATUS_OK;
1756 logoff - close all file descriptors open by a vuid
1758 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1759 struct ntvfs_request *req)
1761 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1762 struct pvfs_state);
1763 struct pvfs_file *f, *next;
1765 /* If pvfs is NULL, we never logged on, and no files are open. */
1766 if(pvfs == NULL) {
1767 return NT_STATUS_OK;
1770 for (f=pvfs->files.list;f;f=next) {
1771 next = f->next;
1772 if (f->ntvfs->session_info == req->session_info) {
1773 talloc_free(f);
1777 return NT_STATUS_OK;
1782 exit - close files for the current pid
1784 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1785 struct ntvfs_request *req)
1787 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
1788 struct pvfs_state);
1789 struct pvfs_file *f, *next;
1791 for (f=pvfs->files.list;f;f=next) {
1792 next = f->next;
1793 if (f->ntvfs->session_info == req->session_info &&
1794 f->ntvfs->smbpid == req->smbpid) {
1795 talloc_free(f);
1799 return NT_STATUS_OK;
1804 change the delete on close flag on an already open file
1806 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1807 struct ntvfs_request *req,
1808 struct pvfs_file *f, bool del_on_close)
1810 struct odb_lock *lck;
1811 NTSTATUS status;
1813 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1814 return NT_STATUS_CANNOT_DELETE;
1817 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1818 !pvfs_directory_empty(pvfs, f->handle->name)) {
1819 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1822 if (del_on_close) {
1823 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1824 } else {
1825 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1828 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1829 if (lck == NULL) {
1830 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1833 status = odb_set_delete_on_close(lck, del_on_close);
1835 talloc_free(lck);
1837 return status;
1842 determine if a file can be deleted, or if it is prevented by an
1843 already open file
1845 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1846 struct ntvfs_request *req,
1847 struct pvfs_filename *name,
1848 struct odb_lock **lckp)
1850 NTSTATUS status;
1851 DATA_BLOB key;
1852 struct odb_lock *lck;
1853 uint32_t share_access;
1854 uint32_t access_mask;
1855 bool delete_on_close;
1857 status = pvfs_locking_key(name, name, &key);
1858 if (!NT_STATUS_IS_OK(status)) {
1859 return NT_STATUS_NO_MEMORY;
1862 lck = odb_lock(req, pvfs->odb_context, &key);
1863 if (lck == NULL) {
1864 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1865 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1868 share_access = NTCREATEX_SHARE_ACCESS_READ |
1869 NTCREATEX_SHARE_ACCESS_WRITE |
1870 NTCREATEX_SHARE_ACCESS_DELETE;
1871 access_mask = SEC_STD_DELETE;
1872 delete_on_close = true;
1874 status = odb_can_open(lck, name->stream_id,
1875 share_access, access_mask, delete_on_close,
1876 NTCREATEX_DISP_OPEN, false);
1878 if (NT_STATUS_IS_OK(status)) {
1879 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1883 * if it's a sharing violation or we got no oplock
1884 * only keep the lock if the caller requested access
1885 * to the lock
1887 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1888 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1889 if (lckp) {
1890 *lckp = lck;
1891 } else {
1892 talloc_free(lck);
1894 } else if (!NT_STATUS_IS_OK(status)) {
1895 talloc_free(lck);
1896 if (lckp) {
1897 *lckp = NULL;
1899 } else if (lckp) {
1900 *lckp = lck;
1903 return status;
1907 determine if a file can be renamed, or if it is prevented by an
1908 already open file
1910 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1911 struct ntvfs_request *req,
1912 struct pvfs_filename *name,
1913 struct odb_lock **lckp)
1915 NTSTATUS status;
1916 DATA_BLOB key;
1917 struct odb_lock *lck;
1918 uint32_t share_access;
1919 uint32_t access_mask;
1920 bool delete_on_close;
1922 status = pvfs_locking_key(name, name, &key);
1923 if (!NT_STATUS_IS_OK(status)) {
1924 return NT_STATUS_NO_MEMORY;
1927 lck = odb_lock(req, pvfs->odb_context, &key);
1928 if (lck == NULL) {
1929 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1930 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1933 share_access = NTCREATEX_SHARE_ACCESS_READ |
1934 NTCREATEX_SHARE_ACCESS_WRITE;
1935 access_mask = SEC_STD_DELETE;
1936 delete_on_close = false;
1938 status = odb_can_open(lck, name->stream_id,
1939 share_access, access_mask, delete_on_close,
1940 NTCREATEX_DISP_OPEN, false);
1943 * if it's a sharing violation or we got no oplock
1944 * only keep the lock if the caller requested access
1945 * to the lock
1947 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1948 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1949 if (lckp) {
1950 *lckp = lck;
1951 } else {
1952 talloc_free(lck);
1954 } else if (!NT_STATUS_IS_OK(status)) {
1955 talloc_free(lck);
1956 if (lckp) {
1957 *lckp = NULL;
1959 } else if (lckp) {
1960 *lckp = lck;
1963 return status;
1967 determine if the file size of a file can be changed,
1968 or if it is prevented by an already open file
1970 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1971 struct ntvfs_request *req,
1972 struct pvfs_filename *name,
1973 struct odb_lock **lckp)
1975 NTSTATUS status;
1976 DATA_BLOB key;
1977 struct odb_lock *lck;
1978 uint32_t share_access;
1979 uint32_t access_mask;
1980 bool break_to_none;
1981 bool delete_on_close;
1983 status = pvfs_locking_key(name, name, &key);
1984 if (!NT_STATUS_IS_OK(status)) {
1985 return NT_STATUS_NO_MEMORY;
1988 lck = odb_lock(req, pvfs->odb_context, &key);
1989 if (lck == NULL) {
1990 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1991 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1994 share_access = NTCREATEX_SHARE_ACCESS_READ |
1995 NTCREATEX_SHARE_ACCESS_WRITE |
1996 NTCREATEX_SHARE_ACCESS_DELETE;
1998 * this code previous set only SEC_FILE_WRITE_ATTRIBUTE, with
1999 * a comment that this seemed to be wrong, but matched windows
2000 * behaviour. It now appears that this windows behaviour is
2001 * just a bug.
2003 access_mask = SEC_FILE_WRITE_ATTRIBUTE | SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA;
2004 delete_on_close = false;
2005 break_to_none = true;
2007 status = odb_can_open(lck, name->stream_id,
2008 share_access, access_mask, delete_on_close,
2009 NTCREATEX_DISP_OPEN, break_to_none);
2012 * if it's a sharing violation or we got no oplock
2013 * only keep the lock if the caller requested access
2014 * to the lock
2016 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
2017 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
2018 if (lckp) {
2019 *lckp = lck;
2020 } else {
2021 talloc_free(lck);
2023 } else if (!NT_STATUS_IS_OK(status)) {
2024 talloc_free(lck);
2025 if (lckp) {
2026 *lckp = NULL;
2028 } else if (lckp) {
2029 *lckp = lck;
2032 return status;
2036 determine if file meta data can be accessed, or if it is prevented by an
2037 already open file
2039 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
2040 struct ntvfs_request *req,
2041 struct pvfs_filename *name)
2043 NTSTATUS status;
2044 DATA_BLOB key;
2045 struct odb_lock *lck;
2046 uint32_t share_access;
2047 uint32_t access_mask;
2048 bool delete_on_close;
2050 status = pvfs_locking_key(name, name, &key);
2051 if (!NT_STATUS_IS_OK(status)) {
2052 return NT_STATUS_NO_MEMORY;
2055 lck = odb_lock(req, pvfs->odb_context, &key);
2056 if (lck == NULL) {
2057 DEBUG(0,("Unable to lock opendb for can_stat\n"));
2058 return NT_STATUS_INTERNAL_DB_CORRUPTION;
2061 share_access = NTCREATEX_SHARE_ACCESS_READ |
2062 NTCREATEX_SHARE_ACCESS_WRITE;
2063 access_mask = SEC_FILE_READ_ATTRIBUTE;
2064 delete_on_close = false;
2066 status = odb_can_open(lck, name->stream_id,
2067 share_access, access_mask, delete_on_close,
2068 NTCREATEX_DISP_OPEN, false);
2070 if (!NT_STATUS_IS_OK(status)) {
2071 talloc_free(lck);
2074 return status;
2079 determine if delete on close is set on
2081 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
2083 NTSTATUS status;
2084 bool del_on_close;
2086 status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key,
2087 &del_on_close, NULL);
2088 if (!NT_STATUS_IS_OK(status)) {
2089 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2090 return false;
2093 return del_on_close;