pvfs: add PVFS_RESOLVE_NO_OPENDB flag and get the write time from the opendb
[Samba/ekacnet.git] / source4 / ntvfs / posix / pvfs_open.c
blob94480df6b72ae4e03dba640f18ff913a1d0ed295
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 (rmdir(delete_path) != 0) {
77 DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
78 delete_path, strerror(errno)));
82 talloc_free(lck);
85 return 0;
89 cleanup a open directory fnum
91 static int pvfs_dir_fnum_destructor(struct pvfs_file *f)
93 DLIST_REMOVE(f->pvfs->files.list, f);
94 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
96 return 0;
100 setup any EAs and the ACL on newly created files/directories
102 static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs,
103 struct ntvfs_request *req,
104 struct pvfs_filename *name,
105 int fd, struct pvfs_file *f,
106 union smb_open *io)
108 NTSTATUS status;
110 /* setup any EAs that were asked for */
111 if (io->ntcreatex.in.ea_list) {
112 status = pvfs_setfileinfo_ea_set(pvfs, name, fd,
113 io->ntcreatex.in.ea_list->num_eas,
114 io->ntcreatex.in.ea_list->eas);
115 if (!NT_STATUS_IS_OK(status)) {
116 return status;
120 /* setup an initial sec_desc if requested */
121 if (io->ntcreatex.in.sec_desc) {
122 union smb_setfileinfo set;
124 * TODO: set the full ACL!
125 * - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD,
126 * when a SACL is present on the sd,
127 * but the user doesn't have SeSecurityPrivilege
128 * - w2k3 allows it
130 set.set_secdesc.in.file.ntvfs = f->ntvfs;
131 set.set_secdesc.in.secinfo_flags = SECINFO_DACL;
132 set.set_secdesc.in.sd = io->ntcreatex.in.sec_desc;
134 status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set);
135 } else {
136 /* otherwise setup an inherited acl from the parent */
137 status = pvfs_acl_inherit(pvfs, req, name, fd);
140 return status;
144 form the lock context used for opendb locking. Note that we must
145 zero here to take account of possible padding on some architectures
147 NTSTATUS pvfs_locking_key(struct pvfs_filename *name,
148 TALLOC_CTX *mem_ctx, DATA_BLOB *key)
150 struct {
151 dev_t device;
152 ino_t inode;
153 } lock_context;
154 ZERO_STRUCT(lock_context);
156 lock_context.device = name->st.st_dev;
157 lock_context.inode = name->st.st_ino;
159 *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context));
160 if (key->data == NULL) {
161 return NT_STATUS_NO_MEMORY;
164 return NT_STATUS_OK;
169 open a directory
171 static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
172 struct ntvfs_request *req,
173 struct pvfs_filename *name,
174 union smb_open *io)
176 struct pvfs_file *f;
177 struct ntvfs_handle *h;
178 NTSTATUS status;
179 uint32_t create_action;
180 uint32_t access_mask = io->generic.in.access_mask;
181 struct odb_lock *lck;
182 bool del_on_close;
183 uint32_t create_options;
184 uint32_t share_access;
185 bool forced;
187 create_options = io->generic.in.create_options;
188 share_access = io->generic.in.share_access;
190 forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false;
192 if (name->stream_name) {
193 if (forced) {
194 return NT_STATUS_NOT_A_DIRECTORY;
195 } else {
196 return NT_STATUS_FILE_IS_A_DIRECTORY;
200 /* if the client says it must be a directory, and it isn't,
201 then fail */
202 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
203 return NT_STATUS_NOT_A_DIRECTORY;
206 /* found with gentest */
207 if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED &&
208 (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) &&
209 (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
210 return NT_STATUS_INVALID_PARAMETER;
213 switch (io->generic.in.open_disposition) {
214 case NTCREATEX_DISP_OPEN_IF:
215 break;
217 case NTCREATEX_DISP_OPEN:
218 if (!name->exists) {
219 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
221 break;
223 case NTCREATEX_DISP_CREATE:
224 if (name->exists) {
225 return NT_STATUS_OBJECT_NAME_COLLISION;
227 break;
229 case NTCREATEX_DISP_OVERWRITE_IF:
230 case NTCREATEX_DISP_OVERWRITE:
231 case NTCREATEX_DISP_SUPERSEDE:
232 default:
233 return NT_STATUS_INVALID_PARAMETER;
236 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
237 NT_STATUS_NOT_OK_RETURN(status);
239 f = talloc(h, struct pvfs_file);
240 if (f == NULL) {
241 return NT_STATUS_NO_MEMORY;
244 f->handle = talloc(f, struct pvfs_file_handle);
245 if (f->handle == NULL) {
246 return NT_STATUS_NO_MEMORY;
249 if (name->exists) {
250 /* check the security descriptor */
251 status = pvfs_access_check(pvfs, req, name, &access_mask);
252 } else {
253 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
255 NT_STATUS_NOT_OK_RETURN(status);
257 if (io->generic.in.query_maximal_access) {
258 status = pvfs_access_maximal_allowed(pvfs, req, name,
259 &io->generic.out.maximal_access);
260 NT_STATUS_NOT_OK_RETURN(status);
263 f->ntvfs = h;
264 f->pvfs = pvfs;
265 f->pending_list = NULL;
266 f->lock_count = 0;
267 f->share_access = io->generic.in.share_access;
268 f->impersonation = io->generic.in.impersonation;
269 f->access_mask = access_mask;
270 f->brl_handle = NULL;
271 f->notify_buffer = NULL;
272 f->search = NULL;
274 f->handle->pvfs = pvfs;
275 f->handle->name = talloc_steal(f->handle, name);
276 f->handle->fd = -1;
277 f->handle->odb_locking_key = data_blob(NULL, 0);
278 f->handle->create_options = io->generic.in.create_options;
279 f->handle->seek_offset = 0;
280 f->handle->position = 0;
281 f->handle->mode = 0;
282 f->handle->oplock = NULL;
283 ZERO_STRUCT(f->handle->write_time);
284 f->handle->open_completed = false;
286 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
287 pvfs_directory_empty(pvfs, f->handle->name)) {
288 del_on_close = true;
289 } else {
290 del_on_close = false;
293 if (name->exists) {
294 /* form the lock context used for opendb locking */
295 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
296 if (!NT_STATUS_IS_OK(status)) {
297 return status;
300 /* get a lock on this file before the actual open */
301 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
302 if (lck == NULL) {
303 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
304 name->full_name));
305 /* we were supposed to do a blocking lock, so something
306 is badly wrong! */
307 return NT_STATUS_INTERNAL_DB_CORRUPTION;
310 /* see if we are allowed to open at the same time as existing opens */
311 status = odb_can_open(lck, name->stream_id,
312 share_access, access_mask, del_on_close,
313 io->generic.in.open_disposition, false);
314 if (!NT_STATUS_IS_OK(status)) {
315 talloc_free(lck);
316 return status;
319 /* now really mark the file as open */
320 status = odb_open_file(lck, f->handle, name->full_name,
321 NULL, name->dos.write_time,
322 false, OPLOCK_NONE, NULL);
324 if (!NT_STATUS_IS_OK(status)) {
325 talloc_free(lck);
326 return status;
329 f->handle->have_opendb_entry = true;
332 DLIST_ADD(pvfs->files.list, f);
334 /* setup destructors to avoid leaks on abnormal termination */
335 talloc_set_destructor(f->handle, pvfs_dir_handle_destructor);
336 talloc_set_destructor(f, pvfs_dir_fnum_destructor);
338 if (!name->exists) {
339 uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY;
340 mode_t mode = pvfs_fileperms(pvfs, attrib);
342 if (mkdir(name->full_name, mode) == -1) {
343 return pvfs_map_errno(pvfs,errno);
346 pvfs_xattr_unlink_hook(pvfs, name->full_name);
348 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
349 if (!NT_STATUS_IS_OK(status)) {
350 goto cleanup_delete;
353 status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io);
354 if (!NT_STATUS_IS_OK(status)) {
355 goto cleanup_delete;
358 /* form the lock context used for opendb locking */
359 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
360 if (!NT_STATUS_IS_OK(status)) {
361 return status;
364 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
365 if (lck == NULL) {
366 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
367 name->full_name));
368 /* we were supposed to do a blocking lock, so something
369 is badly wrong! */
370 return NT_STATUS_INTERNAL_DB_CORRUPTION;
373 status = odb_can_open(lck, name->stream_id,
374 share_access, access_mask, del_on_close,
375 io->generic.in.open_disposition, false);
377 if (!NT_STATUS_IS_OK(status)) {
378 goto cleanup_delete;
381 status = odb_open_file(lck, f->handle, name->full_name,
382 NULL, name->dos.write_time,
383 false, OPLOCK_NONE, NULL);
385 if (!NT_STATUS_IS_OK(status)) {
386 goto cleanup_delete;
389 f->handle->have_opendb_entry = true;
391 create_action = NTCREATEX_ACTION_CREATED;
393 notify_trigger(pvfs->notify_context,
394 NOTIFY_ACTION_ADDED,
395 FILE_NOTIFY_CHANGE_DIR_NAME,
396 name->full_name);
397 } else {
398 create_action = NTCREATEX_ACTION_EXISTED;
401 if (!name->exists) {
402 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
405 /* the open succeeded, keep this handle permanently */
406 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
407 if (!NT_STATUS_IS_OK(status)) {
408 goto cleanup_delete;
411 f->handle->open_completed = true;
413 io->generic.out.oplock_level = OPLOCK_NONE;
414 io->generic.out.file.ntvfs = h;
415 io->generic.out.create_action = create_action;
416 io->generic.out.create_time = name->dos.create_time;
417 io->generic.out.access_time = name->dos.access_time;
418 io->generic.out.write_time = name->dos.write_time;
419 io->generic.out.change_time = name->dos.change_time;
420 io->generic.out.attrib = name->dos.attrib;
421 io->generic.out.alloc_size = name->dos.alloc_size;
422 io->generic.out.size = name->st.st_size;
423 io->generic.out.file_type = FILE_TYPE_DISK;
424 io->generic.out.ipc_state = 0;
425 io->generic.out.is_directory = 1;
427 return NT_STATUS_OK;
429 cleanup_delete:
430 rmdir(name->full_name);
431 return status;
435 destroy a struct pvfs_file_handle
437 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
439 if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
440 h->name->stream_name) {
441 NTSTATUS status;
442 status = pvfs_stream_delete(h->pvfs, h->name, h->fd);
443 if (!NT_STATUS_IS_OK(status)) {
444 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
445 h->name->stream_name, h->name->full_name));
449 if (h->fd != -1) {
450 if (close(h->fd) != 0) {
451 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
452 h->fd, h->name->full_name, strerror(errno)));
454 h->fd = -1;
457 if (h->have_opendb_entry) {
458 struct odb_lock *lck;
459 NTSTATUS status;
460 const char *delete_path = NULL;
462 lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
463 if (lck == NULL) {
464 DEBUG(0,("Unable to lock opendb for close\n"));
465 return 0;
468 status = odb_close_file(lck, h, &delete_path);
469 if (!NT_STATUS_IS_OK(status)) {
470 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
471 h->name->full_name, nt_errstr(status)));
474 if (h->name->stream_name == NULL &&
475 h->open_completed && delete_path) {
476 status = pvfs_xattr_unlink_hook(h->pvfs, delete_path);
477 if (!NT_STATUS_IS_OK(status)) {
478 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
479 delete_path, nt_errstr(status)));
481 if (unlink(delete_path) != 0) {
482 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
483 delete_path, strerror(errno)));
484 } else {
485 notify_trigger(h->pvfs->notify_context,
486 NOTIFY_ACTION_REMOVED,
487 FILE_NOTIFY_CHANGE_FILE_NAME,
488 delete_path);
492 talloc_free(lck);
495 return 0;
500 destroy a struct pvfs_file
502 static int pvfs_fnum_destructor(struct pvfs_file *f)
504 DLIST_REMOVE(f->pvfs->files.list, f);
505 pvfs_lock_close(f->pvfs, f);
506 ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs);
508 return 0;
513 form the lock context used for byte range locking. This is separate
514 from the locking key used for opendb locking as it needs to take
515 account of file streams (each stream is a separate byte range
516 locking space)
518 static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx,
519 struct pvfs_filename *name,
520 struct ntvfs_handle *ntvfs,
521 struct brl_handle **_h)
523 DATA_BLOB odb_key, key;
524 NTSTATUS status;
525 struct brl_handle *h;
527 status = pvfs_locking_key(name, mem_ctx, &odb_key);
528 NT_STATUS_NOT_OK_RETURN(status);
530 if (name->stream_name == NULL) {
531 key = odb_key;
532 } else {
533 key = data_blob_talloc(mem_ctx, NULL,
534 odb_key.length + strlen(name->stream_name) + 1);
535 NT_STATUS_HAVE_NO_MEMORY(key.data);
536 memcpy(key.data, odb_key.data, odb_key.length);
537 memcpy(key.data + odb_key.length,
538 name->stream_name, strlen(name->stream_name) + 1);
539 data_blob_free(&odb_key);
542 h = brl_create_handle(mem_ctx, ntvfs, &key);
543 NT_STATUS_HAVE_NO_MEMORY(h);
545 *_h = h;
546 return NT_STATUS_OK;
550 create a new file
552 static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
553 struct ntvfs_request *req,
554 struct pvfs_filename *name,
555 union smb_open *io)
557 struct pvfs_file *f;
558 NTSTATUS status;
559 struct ntvfs_handle *h;
560 int flags, fd;
561 struct odb_lock *lck;
562 uint32_t create_options = io->generic.in.create_options;
563 uint32_t share_access = io->generic.in.share_access;
564 uint32_t access_mask = io->generic.in.access_mask;
565 mode_t mode;
566 uint32_t attrib;
567 bool del_on_close;
568 struct pvfs_filename *parent;
569 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
570 bool allow_level_II_oplock = false;
572 if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) {
573 return NT_STATUS_INVALID_PARAMETER;
576 if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) {
577 return NT_STATUS_ACCESS_DENIED;
580 if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) &&
581 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
582 return NT_STATUS_CANNOT_DELETE;
585 status = pvfs_access_check_create(pvfs, req, name, &access_mask);
586 NT_STATUS_NOT_OK_RETURN(status);
588 if (io->generic.in.query_maximal_access) {
589 status = pvfs_access_maximal_allowed(pvfs, req, name,
590 &io->generic.out.maximal_access);
591 NT_STATUS_NOT_OK_RETURN(status);
594 /* check that the parent isn't opened with delete on close set */
595 status = pvfs_resolve_parent(pvfs, req, name, &parent);
596 if (NT_STATUS_IS_OK(status)) {
597 DATA_BLOB locking_key;
598 status = pvfs_locking_key(parent, req, &locking_key);
599 NT_STATUS_NOT_OK_RETURN(status);
600 status = odb_get_file_infos(pvfs->odb_context, &locking_key,
601 &del_on_close, NULL);
602 NT_STATUS_NOT_OK_RETURN(status);
603 if (del_on_close) {
604 return NT_STATUS_DELETE_PENDING;
608 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
609 flags = O_RDWR;
610 } else {
611 flags = O_RDONLY;
614 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
615 NT_STATUS_NOT_OK_RETURN(status);
617 f = talloc(h, struct pvfs_file);
618 NT_STATUS_HAVE_NO_MEMORY(f);
620 f->handle = talloc(f, struct pvfs_file_handle);
621 NT_STATUS_HAVE_NO_MEMORY(f->handle);
623 attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
624 mode = pvfs_fileperms(pvfs, attrib);
626 /* create the file */
627 fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
628 if (fd == -1) {
629 return pvfs_map_errno(pvfs, errno);
632 pvfs_xattr_unlink_hook(pvfs, name->full_name);
634 /* if this was a stream create then create the stream as well */
635 if (name->stream_name) {
636 status = pvfs_stream_create(pvfs, name, fd);
637 if (!NT_STATUS_IS_OK(status)) {
638 close(fd);
639 return status;
643 /* re-resolve the open fd */
644 status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
645 if (!NT_STATUS_IS_OK(status)) {
646 close(fd);
647 return status;
650 /* support initial alloc sizes */
651 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
652 name->dos.attrib = attrib;
653 status = pvfs_dosattrib_save(pvfs, name, fd);
654 if (!NT_STATUS_IS_OK(status)) {
655 goto cleanup_delete;
659 status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io);
660 if (!NT_STATUS_IS_OK(status)) {
661 goto cleanup_delete;
664 /* form the lock context used for byte range locking and
665 opendb locking */
666 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
667 if (!NT_STATUS_IS_OK(status)) {
668 goto cleanup_delete;
671 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
672 if (!NT_STATUS_IS_OK(status)) {
673 goto cleanup_delete;
676 /* grab a lock on the open file record */
677 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
678 if (lck == NULL) {
679 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
680 name->full_name));
681 /* we were supposed to do a blocking lock, so something
682 is badly wrong! */
683 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
684 goto cleanup_delete;
687 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) {
688 del_on_close = true;
689 } else {
690 del_on_close = false;
693 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
694 oplock_level = OPLOCK_NONE;
695 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
696 oplock_level = OPLOCK_BATCH;
697 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
698 oplock_level = OPLOCK_EXCLUSIVE;
701 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
702 allow_level_II_oplock = true;
705 status = odb_can_open(lck, name->stream_id,
706 share_access, access_mask, del_on_close,
707 io->generic.in.open_disposition, false);
708 if (!NT_STATUS_IS_OK(status)) {
709 talloc_free(lck);
710 /* bad news, we must have hit a race - we don't delete the file
711 here as the most likely scenario is that someone else created
712 the file at the same time */
713 close(fd);
714 return status;
717 f->ntvfs = h;
718 f->pvfs = pvfs;
719 f->pending_list = NULL;
720 f->lock_count = 0;
721 f->share_access = io->generic.in.share_access;
722 f->access_mask = access_mask;
723 f->impersonation = io->generic.in.impersonation;
724 f->notify_buffer = NULL;
725 f->search = NULL;
727 f->handle->pvfs = pvfs;
728 f->handle->name = talloc_steal(f->handle, name);
729 f->handle->fd = fd;
730 f->handle->create_options = io->generic.in.create_options;
731 f->handle->seek_offset = 0;
732 f->handle->position = 0;
733 f->handle->mode = 0;
734 f->handle->oplock = NULL;
735 f->handle->have_opendb_entry = true;
736 ZERO_STRUCT(f->handle->write_time);
737 f->handle->open_completed = false;
739 status = odb_open_file(lck, f->handle, name->full_name,
740 &f->handle->fd, name->dos.write_time,
741 allow_level_II_oplock,
742 oplock_level, &oplock_granted);
743 talloc_free(lck);
744 if (!NT_STATUS_IS_OK(status)) {
745 /* bad news, we must have hit a race - we don't delete the file
746 here as the most likely scenario is that someone else created
747 the file at the same time */
748 close(fd);
749 return status;
752 DLIST_ADD(pvfs->files.list, f);
754 /* setup a destructor to avoid file descriptor leaks on
755 abnormal termination */
756 talloc_set_destructor(f, pvfs_fnum_destructor);
757 talloc_set_destructor(f->handle, pvfs_handle_destructor);
759 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
760 oplock_granted = OPLOCK_BATCH;
761 } else if (oplock_granted != OPLOCK_NONE) {
762 status = pvfs_setup_oplock(f, oplock_granted);
763 if (!NT_STATUS_IS_OK(status)) {
764 return status;
768 io->generic.out.oplock_level = oplock_granted;
769 io->generic.out.file.ntvfs = f->ntvfs;
770 io->generic.out.create_action = NTCREATEX_ACTION_CREATED;
771 io->generic.out.create_time = name->dos.create_time;
772 io->generic.out.access_time = name->dos.access_time;
773 io->generic.out.write_time = name->dos.write_time;
774 io->generic.out.change_time = name->dos.change_time;
775 io->generic.out.attrib = name->dos.attrib;
776 io->generic.out.alloc_size = name->dos.alloc_size;
777 io->generic.out.size = name->st.st_size;
778 io->generic.out.file_type = FILE_TYPE_DISK;
779 io->generic.out.ipc_state = 0;
780 io->generic.out.is_directory = 0;
782 /* success - keep the file handle */
783 status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f);
784 if (!NT_STATUS_IS_OK(status)) {
785 goto cleanup_delete;
788 f->handle->open_completed = true;
790 notify_trigger(pvfs->notify_context,
791 NOTIFY_ACTION_ADDED,
792 FILE_NOTIFY_CHANGE_FILE_NAME,
793 name->full_name);
795 return NT_STATUS_OK;
797 cleanup_delete:
798 close(fd);
799 unlink(name->full_name);
800 return status;
804 state of a pending retry
806 struct pvfs_odb_retry {
807 struct ntvfs_module_context *ntvfs;
808 struct ntvfs_request *req;
809 DATA_BLOB odb_locking_key;
810 void *io;
811 void *private_data;
812 void (*callback)(struct pvfs_odb_retry *r,
813 struct ntvfs_module_context *ntvfs,
814 struct ntvfs_request *req,
815 void *io,
816 void *private_data,
817 enum pvfs_wait_notice reason);
820 /* destroy a pending request */
821 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
823 struct pvfs_state *pvfs = r->ntvfs->private_data;
824 if (r->odb_locking_key.data) {
825 struct odb_lock *lck;
826 lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key);
827 if (lck != NULL) {
828 odb_remove_pending(lck, r);
830 talloc_free(lck);
832 return 0;
835 static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
837 struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
839 if (reason == PVFS_WAIT_EVENT) {
841 * The pending odb entry is already removed.
842 * We use a null locking key to indicate this
843 * to the destructor.
845 data_blob_free(&r->odb_locking_key);
848 r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
852 setup for a retry of a request that was rejected
853 by odb_can_open()
855 NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
856 struct ntvfs_request *req,
857 struct odb_lock *lck,
858 struct timeval end_time,
859 void *io,
860 void *private_data,
861 void (*callback)(struct pvfs_odb_retry *r,
862 struct ntvfs_module_context *ntvfs,
863 struct ntvfs_request *req,
864 void *io,
865 void *private_data,
866 enum pvfs_wait_notice reason))
868 struct pvfs_state *pvfs = ntvfs->private_data;
869 struct pvfs_odb_retry *r;
870 struct pvfs_wait *wait_handle;
871 NTSTATUS status;
873 r = talloc(req, struct pvfs_odb_retry);
874 NT_STATUS_HAVE_NO_MEMORY(r);
876 r->ntvfs = ntvfs;
877 r->req = req;
878 r->io = io;
879 r->private_data = private_data;
880 r->callback = callback;
881 r->odb_locking_key = odb_get_key(r, lck);
882 if (r->odb_locking_key.data == NULL) {
883 return NT_STATUS_NO_MEMORY;
886 /* setup a pending lock */
887 status = odb_open_file_pending(lck, r);
888 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
890 * maybe only a unix application
891 * has the file open
893 data_blob_free(&r->odb_locking_key);
894 } else if (!NT_STATUS_IS_OK(status)) {
895 return status;
898 talloc_free(lck);
900 talloc_set_destructor(r, pvfs_odb_retry_destructor);
902 wait_handle = pvfs_wait_message(pvfs, req,
903 MSG_PVFS_RETRY_OPEN, end_time,
904 pvfs_odb_retry_callback, r);
905 if (wait_handle == NULL) {
906 return NT_STATUS_NO_MEMORY;
909 talloc_steal(r, wait_handle);
911 return NT_STATUS_OK;
915 retry an open after a sharing violation
917 static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
918 struct ntvfs_module_context *ntvfs,
919 struct ntvfs_request *req,
920 void *_io,
921 void *private_data,
922 enum pvfs_wait_notice reason)
924 union smb_open *io = talloc_get_type(_io, union smb_open);
925 struct timeval *final_timeout = NULL;
926 NTSTATUS status;
928 if (private_data) {
929 final_timeout = talloc_get_type(private_data,
930 struct timeval);
933 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
934 just a bug in their server, but we better do the same */
935 if (reason == PVFS_WAIT_CANCEL) {
936 return;
939 if (reason == PVFS_WAIT_TIMEOUT) {
940 if (final_timeout &&
941 !timeval_expired(final_timeout)) {
943 * we need to retry periodictly
944 * after an EAGAIN as there's
945 * no way the kernel tell us
946 * an oplock is released.
948 goto retry;
950 /* if it timed out, then give the failure
951 immediately */
952 talloc_free(r);
953 req->async_states->status = NT_STATUS_SHARING_VIOLATION;
954 req->async_states->send_fn(req);
955 return;
958 retry:
959 talloc_free(r);
961 /* try the open again, which could trigger another retry setup
962 if it wants to, so we have to unmark the async flag so we
963 will know if it does a second async reply */
964 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
966 status = pvfs_open(ntvfs, req, io);
967 if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
968 /* the 2nd try also replied async, so we don't send
969 the reply yet */
970 return;
973 /* re-mark it async, just in case someone up the chain does
974 paranoid checking */
975 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
977 /* send the reply up the chain */
978 req->async_states->status = status;
979 req->async_states->send_fn(req);
984 special handling for openx DENY_DOS semantics
986 This function attempts a reference open using an existing handle. If its allowed,
987 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
988 open processing continues.
990 static NTSTATUS pvfs_open_deny_dos(struct ntvfs_module_context *ntvfs,
991 struct ntvfs_request *req, union smb_open *io,
992 struct pvfs_file *f, struct odb_lock *lck)
994 struct pvfs_state *pvfs = ntvfs->private_data;
995 struct pvfs_file *f2;
996 struct pvfs_filename *name;
997 NTSTATUS status;
999 /* search for an existing open with the right parameters. Note
1000 the magic ntcreatex options flag, which is set in the
1001 generic mapping code. This might look ugly, but its
1002 actually pretty much now w2k does it internally as well.
1004 If you look at the BASE-DENYDOS test you will see that a
1005 DENY_DOS is a very special case, and in the right
1006 circumstances you actually get the _same_ handle back
1007 twice, rather than a new handle.
1009 for (f2=pvfs->files.list;f2;f2=f2->next) {
1010 if (f2 != f &&
1011 f2->ntvfs->session_info == req->session_info &&
1012 f2->ntvfs->smbpid == req->smbpid &&
1013 (f2->handle->create_options &
1014 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
1015 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) &&
1016 (f2->access_mask & SEC_FILE_WRITE_DATA) &&
1017 strcasecmp_m(f2->handle->name->original_name,
1018 io->generic.in.fname)==0) {
1019 break;
1023 if (!f2) {
1024 return NT_STATUS_SHARING_VIOLATION;
1027 /* quite an insane set of semantics ... */
1028 if (is_exe_filename(io->generic.in.fname) &&
1029 (f2->handle->create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
1030 return NT_STATUS_SHARING_VIOLATION;
1034 setup a reference to the existing handle
1036 talloc_free(f->handle);
1037 f->handle = talloc_reference(f, f2->handle);
1039 talloc_free(lck);
1041 name = f->handle->name;
1043 io->generic.out.oplock_level = OPLOCK_NONE;
1044 io->generic.out.file.ntvfs = f->ntvfs;
1045 io->generic.out.create_action = NTCREATEX_ACTION_EXISTED;
1046 io->generic.out.create_time = name->dos.create_time;
1047 io->generic.out.access_time = name->dos.access_time;
1048 io->generic.out.write_time = name->dos.write_time;
1049 io->generic.out.change_time = name->dos.change_time;
1050 io->generic.out.attrib = name->dos.attrib;
1051 io->generic.out.alloc_size = name->dos.alloc_size;
1052 io->generic.out.size = name->st.st_size;
1053 io->generic.out.file_type = FILE_TYPE_DISK;
1054 io->generic.out.ipc_state = 0;
1055 io->generic.out.is_directory = 0;
1057 status = ntvfs_handle_set_backend_data(f->ntvfs, ntvfs, f);
1058 NT_STATUS_NOT_OK_RETURN(status);
1060 return NT_STATUS_OK;
1066 setup for a open retry after a sharing violation
1068 static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
1069 struct ntvfs_request *req,
1070 union smb_open *io,
1071 struct pvfs_file *f,
1072 struct odb_lock *lck,
1073 NTSTATUS parent_status)
1075 struct pvfs_state *pvfs = ntvfs->private_data;
1076 NTSTATUS status;
1077 struct timeval end_time;
1078 struct timeval *final_timeout = NULL;
1080 if (io->generic.in.create_options &
1081 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
1082 /* see if we can satisfy the request using the special DENY_DOS
1083 code */
1084 status = pvfs_open_deny_dos(ntvfs, req, io, f, lck);
1085 if (NT_STATUS_IS_OK(status)) {
1086 return status;
1090 /* the retry should allocate a new file handle */
1091 talloc_free(f);
1093 if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
1094 end_time = timeval_add(&req->statistics.request_time,
1095 0, pvfs->sharing_violation_delay);
1096 } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1097 end_time = timeval_add(&req->statistics.request_time,
1098 pvfs->oplock_break_timeout, 0);
1099 } else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
1101 * we got EAGAIN which means a unix application
1102 * has an oplock or share mode
1104 * we retry every 4/5 of the sharing violation delay
1105 * to see if the unix application
1106 * has released the oplock or share mode.
1108 final_timeout = talloc(req, struct timeval);
1109 NT_STATUS_HAVE_NO_MEMORY(final_timeout);
1110 *final_timeout = timeval_add(&req->statistics.request_time,
1111 pvfs->oplock_break_timeout,
1113 end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
1114 end_time = timeval_min(final_timeout, &end_time);
1115 } else {
1116 return NT_STATUS_INTERNAL_ERROR;
1119 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
1120 final_timeout, pvfs_retry_open_sharing);
1124 open a file
1126 NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
1127 struct ntvfs_request *req, union smb_open *io)
1129 struct pvfs_state *pvfs = ntvfs->private_data;
1130 int flags;
1131 struct pvfs_filename *name;
1132 struct pvfs_file *f;
1133 struct ntvfs_handle *h;
1134 NTSTATUS status;
1135 int fd;
1136 struct odb_lock *lck;
1137 uint32_t create_options;
1138 uint32_t share_access;
1139 uint32_t access_mask;
1140 uint32_t create_action = NTCREATEX_ACTION_EXISTED;
1141 bool del_on_close;
1142 bool stream_existed, stream_truncate=false;
1143 uint32_t oplock_level = OPLOCK_NONE, oplock_granted;
1144 bool allow_level_II_oplock = false;
1146 /* use the generic mapping code to avoid implementing all the
1147 different open calls. */
1148 if (io->generic.level != RAW_OPEN_GENERIC &&
1149 io->generic.level != RAW_OPEN_NTTRANS_CREATE) {
1150 return ntvfs_map_open(ntvfs, req, io);
1153 ZERO_STRUCT(io->generic.out);
1155 create_options = io->generic.in.create_options;
1156 share_access = io->generic.in.share_access;
1157 access_mask = io->generic.in.access_mask;
1159 if (share_access & ~NTCREATEX_SHARE_ACCESS_MASK) {
1160 return NT_STATUS_INVALID_PARAMETER;
1163 /* some create options are not supported */
1164 if (create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) {
1165 return NT_STATUS_NOT_SUPPORTED;
1168 /* other create options are not allowed */
1169 if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
1170 !(access_mask & SEC_STD_DELETE)) {
1171 return NT_STATUS_INVALID_PARAMETER;
1174 if (access_mask & SEC_MASK_INVALID) {
1175 return NT_STATUS_ACCESS_DENIED;
1178 /* what does this bit really mean?? */
1179 if (req->ctx->protocol == PROTOCOL_SMB2 &&
1180 access_mask == SEC_STD_SYNCHRONIZE) {
1181 return NT_STATUS_ACCESS_DENIED;
1184 if (io->ntcreatex.in.file_attr & (FILE_ATTRIBUTE_DEVICE|
1185 FILE_ATTRIBUTE_VOLUME|
1186 (~FILE_ATTRIBUTE_ALL_MASK))) {
1187 return NT_STATUS_INVALID_PARAMETER;
1190 /* we ignore some file_attr bits */
1191 io->ntcreatex.in.file_attr &= ~(FILE_ATTRIBUTE_NONINDEXED |
1192 FILE_ATTRIBUTE_COMPRESSED |
1193 FILE_ATTRIBUTE_REPARSE_POINT |
1194 FILE_ATTRIBUTE_SPARSE |
1195 FILE_ATTRIBUTE_NORMAL);
1197 /* resolve the cifs name to a posix name */
1198 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname,
1199 PVFS_RESOLVE_STREAMS, &name);
1200 if (!NT_STATUS_IS_OK(status)) {
1201 return status;
1204 /* if the client specified that it must not be a directory then
1205 check that it isn't */
1206 if (name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1207 (io->generic.in.create_options & NTCREATEX_OPTIONS_NON_DIRECTORY_FILE)) {
1208 return NT_STATUS_FILE_IS_A_DIRECTORY;
1211 /* if the client specified that it must be a directory then
1212 check that it is */
1213 if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1214 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1215 return NT_STATUS_NOT_A_DIRECTORY;
1218 /* directory opens are handled separately */
1219 if ((name->exists && (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) ||
1220 (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)) {
1221 return pvfs_open_directory(pvfs, req, name, io);
1224 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1225 open doesn't match */
1226 io->generic.in.file_attr &= ~FILE_ATTRIBUTE_DIRECTORY;
1228 flags = 0;
1230 switch (io->generic.in.open_disposition) {
1231 case NTCREATEX_DISP_SUPERSEDE:
1232 case NTCREATEX_DISP_OVERWRITE_IF:
1233 if (name->stream_name == NULL) {
1234 flags = O_TRUNC;
1235 } else {
1236 stream_truncate = true;
1238 create_action = NTCREATEX_ACTION_TRUNCATED;
1239 break;
1241 case NTCREATEX_DISP_OPEN:
1242 if (!name->stream_exists) {
1243 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1245 flags = 0;
1246 break;
1248 case NTCREATEX_DISP_OVERWRITE:
1249 if (!name->stream_exists) {
1250 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1252 if (name->stream_name == NULL) {
1253 flags = O_TRUNC;
1254 } else {
1255 stream_truncate = true;
1257 create_action = NTCREATEX_ACTION_TRUNCATED;
1258 break;
1260 case NTCREATEX_DISP_CREATE:
1261 if (name->stream_exists) {
1262 return NT_STATUS_OBJECT_NAME_COLLISION;
1264 flags = 0;
1265 break;
1267 case NTCREATEX_DISP_OPEN_IF:
1268 flags = 0;
1269 break;
1271 default:
1272 return NT_STATUS_INVALID_PARAMETER;
1275 /* handle creating a new file separately */
1276 if (!name->exists) {
1277 status = pvfs_create_file(pvfs, req, name, io);
1278 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
1279 return status;
1282 /* we've hit a race - the file was created during this call */
1283 if (io->generic.in.open_disposition == NTCREATEX_DISP_CREATE) {
1284 return status;
1287 /* try re-resolving the name */
1288 status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name);
1289 if (!NT_STATUS_IS_OK(status)) {
1290 return status;
1292 /* fall through to a normal open */
1295 if ((name->dos.attrib & FILE_ATTRIBUTE_READONLY) &&
1296 (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) {
1297 return NT_STATUS_CANNOT_DELETE;
1300 /* check the security descriptor */
1301 status = pvfs_access_check(pvfs, req, name, &access_mask);
1302 NT_STATUS_NOT_OK_RETURN(status);
1304 if (io->generic.in.query_maximal_access) {
1305 status = pvfs_access_maximal_allowed(pvfs, req, name,
1306 &io->generic.out.maximal_access);
1307 NT_STATUS_NOT_OK_RETURN(status);
1310 status = ntvfs_handle_new(pvfs->ntvfs, req, &h);
1311 NT_STATUS_NOT_OK_RETURN(status);
1313 f = talloc(h, struct pvfs_file);
1314 if (f == NULL) {
1315 return NT_STATUS_NO_MEMORY;
1318 f->handle = talloc(f, struct pvfs_file_handle);
1319 if (f->handle == NULL) {
1320 return NT_STATUS_NO_MEMORY;
1323 f->ntvfs = h;
1324 f->pvfs = pvfs;
1325 f->pending_list = NULL;
1326 f->lock_count = 0;
1327 f->share_access = io->generic.in.share_access;
1328 f->access_mask = access_mask;
1329 f->impersonation = io->generic.in.impersonation;
1330 f->notify_buffer = NULL;
1331 f->search = NULL;
1333 f->handle->pvfs = pvfs;
1334 f->handle->fd = -1;
1335 f->handle->name = talloc_steal(f->handle, name);
1336 f->handle->create_options = io->generic.in.create_options;
1337 f->handle->seek_offset = 0;
1338 f->handle->position = 0;
1339 f->handle->mode = 0;
1340 f->handle->oplock = NULL;
1341 f->handle->have_opendb_entry = false;
1342 ZERO_STRUCT(f->handle->write_time);
1343 f->handle->open_completed = false;
1345 /* form the lock context used for byte range locking and
1346 opendb locking */
1347 status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key);
1348 if (!NT_STATUS_IS_OK(status)) {
1349 return status;
1352 status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle);
1353 if (!NT_STATUS_IS_OK(status)) {
1354 return status;
1357 /* get a lock on this file before the actual open */
1358 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1359 if (lck == NULL) {
1360 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1361 name->full_name));
1362 /* we were supposed to do a blocking lock, so something
1363 is badly wrong! */
1364 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1367 DLIST_ADD(pvfs->files.list, f);
1369 /* setup a destructor to avoid file descriptor leaks on
1370 abnormal termination */
1371 talloc_set_destructor(f, pvfs_fnum_destructor);
1372 talloc_set_destructor(f->handle, pvfs_handle_destructor);
1375 * Only SMB2 takes care of the delete_on_close,
1376 * on existing files
1378 if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE &&
1379 req->ctx->protocol == PROTOCOL_SMB2) {
1380 del_on_close = true;
1381 } else {
1382 del_on_close = false;
1385 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1386 oplock_level = OPLOCK_NONE;
1387 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) {
1388 oplock_level = OPLOCK_BATCH;
1389 } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) {
1390 oplock_level = OPLOCK_EXCLUSIVE;
1393 if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) {
1394 allow_level_II_oplock = true;
1397 /* see if we are allowed to open at the same time as existing opens */
1398 status = odb_can_open(lck, name->stream_id,
1399 share_access, access_mask, del_on_close,
1400 io->generic.in.open_disposition, false);
1403 * on a sharing violation we need to retry when the file is closed by
1404 * the other user, or after 1 second
1405 * on a non granted oplock we need to retry when the file is closed by
1406 * the other user, or after 30 seconds
1408 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1409 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
1410 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1411 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1414 if (!NT_STATUS_IS_OK(status)) {
1415 talloc_free(lck);
1416 return status;
1419 if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
1420 flags |= O_RDWR;
1421 } else {
1422 flags |= O_RDONLY;
1425 /* do the actual open */
1426 fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
1427 if (fd == -1) {
1428 status = pvfs_map_errno(f->pvfs, errno);
1431 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1433 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
1434 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
1435 return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
1438 talloc_free(lck);
1439 return status;
1442 f->handle->fd = fd;
1444 /* now really mark the file as open */
1445 status = odb_open_file(lck, f->handle, name->full_name,
1446 &f->handle->fd, name->dos.write_time,
1447 allow_level_II_oplock,
1448 oplock_level, &oplock_granted);
1450 if (!NT_STATUS_IS_OK(status)) {
1451 talloc_free(lck);
1452 return status;
1455 f->handle->have_opendb_entry = true;
1457 if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
1458 oplock_granted = OPLOCK_BATCH;
1459 } else if (oplock_granted != OPLOCK_NONE) {
1460 status = pvfs_setup_oplock(f, oplock_granted);
1461 if (!NT_STATUS_IS_OK(status)) {
1462 talloc_free(lck);
1463 return status;
1467 stream_existed = name->stream_exists;
1469 /* if this was a stream create then create the stream as well */
1470 if (!name->stream_exists) {
1471 status = pvfs_stream_create(pvfs, f->handle->name, fd);
1472 if (!NT_STATUS_IS_OK(status)) {
1473 talloc_free(lck);
1474 return status;
1476 if (stream_truncate) {
1477 status = pvfs_stream_truncate(pvfs, f->handle->name, fd, 0);
1478 if (!NT_STATUS_IS_OK(status)) {
1479 talloc_free(lck);
1480 return status;
1485 /* re-resolve the open fd */
1486 status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
1487 if (!NT_STATUS_IS_OK(status)) {
1488 talloc_free(lck);
1489 return status;
1492 if (f->handle->name->stream_id == 0 &&
1493 (io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE ||
1494 io->generic.in.open_disposition == NTCREATEX_DISP_OVERWRITE_IF)) {
1495 /* for overwrite we need to replace file permissions */
1496 uint32_t attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE;
1497 mode_t mode = pvfs_fileperms(pvfs, attrib);
1498 if (fchmod(fd, mode) == -1) {
1499 talloc_free(lck);
1500 return pvfs_map_errno(pvfs, errno);
1502 name->dos.alloc_size = io->ntcreatex.in.alloc_size;
1503 name->dos.attrib = attrib;
1504 status = pvfs_dosattrib_save(pvfs, name, fd);
1505 if (!NT_STATUS_IS_OK(status)) {
1506 talloc_free(lck);
1507 return status;
1511 talloc_free(lck);
1513 status = ntvfs_handle_set_backend_data(h, ntvfs, f);
1514 NT_STATUS_NOT_OK_RETURN(status);
1516 /* mark the open as having completed fully, so delete on close
1517 can now be used */
1518 f->handle->open_completed = true;
1520 io->generic.out.oplock_level = oplock_granted;
1521 io->generic.out.file.ntvfs = h;
1522 io->generic.out.create_action = stream_existed?
1523 create_action:NTCREATEX_ACTION_CREATED;
1525 io->generic.out.create_time = name->dos.create_time;
1526 io->generic.out.access_time = name->dos.access_time;
1527 io->generic.out.write_time = name->dos.write_time;
1528 io->generic.out.change_time = name->dos.change_time;
1529 io->generic.out.attrib = name->dos.attrib;
1530 io->generic.out.alloc_size = name->dos.alloc_size;
1531 io->generic.out.size = name->st.st_size;
1532 io->generic.out.file_type = FILE_TYPE_DISK;
1533 io->generic.out.ipc_state = 0;
1534 io->generic.out.is_directory = 0;
1536 return NT_STATUS_OK;
1541 close a file
1543 NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
1544 struct ntvfs_request *req, union smb_close *io)
1546 struct pvfs_state *pvfs = ntvfs->private_data;
1547 struct pvfs_file *f;
1548 struct utimbuf unix_times;
1550 if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
1551 return NT_STATUS_DOS(ERRSRV, ERRerror);
1554 if (io->generic.level != RAW_CLOSE_GENERIC) {
1555 return ntvfs_map_close(ntvfs, req, io);
1558 f = pvfs_find_fd(pvfs, req, io->generic.in.file.ntvfs);
1559 if (!f) {
1560 return NT_STATUS_INVALID_HANDLE;
1563 if (!null_time(io->generic.in.write_time)) {
1564 unix_times.actime = 0;
1565 unix_times.modtime = io->close.in.write_time;
1566 utime(f->handle->name->full_name, &unix_times);
1569 if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
1570 struct pvfs_filename *name;
1571 NTSTATUS status;
1572 struct pvfs_file_handle *h = f->handle;
1574 status = pvfs_resolve_name_handle(pvfs, h);
1575 if (!NT_STATUS_IS_OK(status)) {
1576 return status;
1578 name = h->name;
1580 io->generic.out.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
1581 io->generic.out.create_time = name->dos.create_time;
1582 io->generic.out.access_time = name->dos.access_time;
1583 io->generic.out.write_time = name->dos.write_time;
1584 io->generic.out.change_time = name->dos.change_time;
1585 io->generic.out.alloc_size = name->dos.alloc_size;
1586 io->generic.out.size = name->st.st_size;
1587 io->generic.out.file_attr = name->dos.attrib;
1588 } else {
1589 ZERO_STRUCT(io->generic.out);
1592 talloc_free(f);
1594 return NT_STATUS_OK;
1599 logoff - close all file descriptors open by a vuid
1601 NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
1602 struct ntvfs_request *req)
1604 struct pvfs_state *pvfs = ntvfs->private_data;
1605 struct pvfs_file *f, *next;
1607 for (f=pvfs->files.list;f;f=next) {
1608 next = f->next;
1609 if (f->ntvfs->session_info == req->session_info) {
1610 talloc_free(f);
1614 return NT_STATUS_OK;
1619 exit - close files for the current pid
1621 NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
1622 struct ntvfs_request *req)
1624 struct pvfs_state *pvfs = ntvfs->private_data;
1625 struct pvfs_file *f, *next;
1627 for (f=pvfs->files.list;f;f=next) {
1628 next = f->next;
1629 if (f->ntvfs->session_info == req->session_info &&
1630 f->ntvfs->smbpid == req->smbpid) {
1631 talloc_free(f);
1635 return NT_STATUS_OK;
1640 change the delete on close flag on an already open file
1642 NTSTATUS pvfs_set_delete_on_close(struct pvfs_state *pvfs,
1643 struct ntvfs_request *req,
1644 struct pvfs_file *f, bool del_on_close)
1646 struct odb_lock *lck;
1647 NTSTATUS status;
1649 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_READONLY) && del_on_close) {
1650 return NT_STATUS_CANNOT_DELETE;
1653 if ((f->handle->name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
1654 !pvfs_directory_empty(pvfs, f->handle->name)) {
1655 return NT_STATUS_DIRECTORY_NOT_EMPTY;
1658 if (del_on_close) {
1659 f->handle->create_options |= NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1660 } else {
1661 f->handle->create_options &= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
1664 lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key);
1665 if (lck == NULL) {
1666 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1669 status = odb_set_delete_on_close(lck, del_on_close);
1671 talloc_free(lck);
1673 return status;
1678 determine if a file can be deleted, or if it is prevented by an
1679 already open file
1681 NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
1682 struct ntvfs_request *req,
1683 struct pvfs_filename *name,
1684 struct odb_lock **lckp)
1686 NTSTATUS status;
1687 DATA_BLOB key;
1688 struct odb_lock *lck;
1689 uint32_t share_access;
1690 uint32_t access_mask;
1691 bool delete_on_close;
1693 status = pvfs_locking_key(name, name, &key);
1694 if (!NT_STATUS_IS_OK(status)) {
1695 return NT_STATUS_NO_MEMORY;
1698 lck = odb_lock(req, pvfs->odb_context, &key);
1699 if (lck == NULL) {
1700 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1701 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1704 share_access = NTCREATEX_SHARE_ACCESS_READ |
1705 NTCREATEX_SHARE_ACCESS_WRITE |
1706 NTCREATEX_SHARE_ACCESS_DELETE;
1707 access_mask = SEC_STD_DELETE;
1708 delete_on_close = true;
1710 status = odb_can_open(lck, name->stream_id,
1711 share_access, access_mask, delete_on_close,
1712 NTCREATEX_DISP_OPEN, false);
1714 if (NT_STATUS_IS_OK(status)) {
1715 status = pvfs_access_check_simple(pvfs, req, name, access_mask);
1719 * if it's a sharing violation or we got no oplock
1720 * only keep the lock if the caller requested access
1721 * to the lock
1723 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1724 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1725 if (lckp) {
1726 *lckp = lck;
1727 } else {
1728 talloc_free(lck);
1730 } else if (!NT_STATUS_IS_OK(status)) {
1731 talloc_free(lck);
1732 if (lckp) {
1733 *lckp = NULL;
1735 } else if (lckp) {
1736 *lckp = lck;
1739 return status;
1743 determine if a file can be renamed, or if it is prevented by an
1744 already open file
1746 NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
1747 struct ntvfs_request *req,
1748 struct pvfs_filename *name,
1749 struct odb_lock **lckp)
1751 NTSTATUS status;
1752 DATA_BLOB key;
1753 struct odb_lock *lck;
1754 uint32_t share_access;
1755 uint32_t access_mask;
1756 bool delete_on_close;
1758 status = pvfs_locking_key(name, name, &key);
1759 if (!NT_STATUS_IS_OK(status)) {
1760 return NT_STATUS_NO_MEMORY;
1763 lck = odb_lock(req, pvfs->odb_context, &key);
1764 if (lck == NULL) {
1765 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1766 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1769 share_access = NTCREATEX_SHARE_ACCESS_READ |
1770 NTCREATEX_SHARE_ACCESS_WRITE;
1771 access_mask = SEC_STD_DELETE;
1772 delete_on_close = false;
1774 status = odb_can_open(lck, name->stream_id,
1775 share_access, access_mask, delete_on_close,
1776 NTCREATEX_DISP_OPEN, false);
1779 * if it's a sharing violation or we got no oplock
1780 * only keep the lock if the caller requested access
1781 * to the lock
1783 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1784 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1785 if (lckp) {
1786 *lckp = lck;
1787 } else {
1788 talloc_free(lck);
1790 } else if (!NT_STATUS_IS_OK(status)) {
1791 talloc_free(lck);
1792 if (lckp) {
1793 *lckp = NULL;
1795 } else if (lckp) {
1796 *lckp = lck;
1799 return status;
1803 determine if the file size of a file can be changed,
1804 or if it is prevented by an already open file
1806 NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
1807 struct ntvfs_request *req,
1808 struct pvfs_filename *name,
1809 struct odb_lock **lckp)
1811 NTSTATUS status;
1812 DATA_BLOB key;
1813 struct odb_lock *lck;
1814 uint32_t share_access;
1815 uint32_t access_mask;
1816 bool break_to_none;
1817 bool delete_on_close;
1819 status = pvfs_locking_key(name, name, &key);
1820 if (!NT_STATUS_IS_OK(status)) {
1821 return NT_STATUS_NO_MEMORY;
1824 lck = odb_lock(req, pvfs->odb_context, &key);
1825 if (lck == NULL) {
1826 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1827 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1830 share_access = NTCREATEX_SHARE_ACCESS_READ |
1831 NTCREATEX_SHARE_ACCESS_WRITE |
1832 NTCREATEX_SHARE_ACCESS_DELETE;
1834 * I would have thought that we would need to pass
1835 * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
1837 * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
1838 * to set the filesize.
1840 * --metze
1842 access_mask = SEC_FILE_WRITE_ATTRIBUTE;
1843 delete_on_close = false;
1844 break_to_none = true;
1846 status = odb_can_open(lck, name->stream_id,
1847 share_access, access_mask, delete_on_close,
1848 NTCREATEX_DISP_OPEN, break_to_none);
1851 * if it's a sharing violation or we got no oplock
1852 * only keep the lock if the caller requested access
1853 * to the lock
1855 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
1856 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
1857 if (lckp) {
1858 *lckp = lck;
1859 } else {
1860 talloc_free(lck);
1862 } else if (!NT_STATUS_IS_OK(status)) {
1863 talloc_free(lck);
1864 if (lckp) {
1865 *lckp = NULL;
1867 } else if (lckp) {
1868 *lckp = lck;
1871 return status;
1875 determine if file meta data can be accessed, or if it is prevented by an
1876 already open file
1878 NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
1879 struct ntvfs_request *req,
1880 struct pvfs_filename *name)
1882 NTSTATUS status;
1883 DATA_BLOB key;
1884 struct odb_lock *lck;
1885 uint32_t share_access;
1886 uint32_t access_mask;
1887 bool delete_on_close;
1889 status = pvfs_locking_key(name, name, &key);
1890 if (!NT_STATUS_IS_OK(status)) {
1891 return NT_STATUS_NO_MEMORY;
1894 lck = odb_lock(req, pvfs->odb_context, &key);
1895 if (lck == NULL) {
1896 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1897 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1900 share_access = NTCREATEX_SHARE_ACCESS_READ |
1901 NTCREATEX_SHARE_ACCESS_WRITE;
1902 access_mask = SEC_FILE_READ_ATTRIBUTE;
1903 delete_on_close = false;
1905 status = odb_can_open(lck, name->stream_id,
1906 share_access, access_mask, delete_on_close,
1907 NTCREATEX_DISP_OPEN, false);
1909 if (!NT_STATUS_IS_OK(status)) {
1910 talloc_free(lck);
1913 return status;
1918 determine if delete on close is set on
1920 bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *h)
1922 NTSTATUS status;
1923 bool del_on_close;
1925 status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key,
1926 &del_on_close, NULL);
1927 if (!NT_STATUS_IS_OK(status)) {
1928 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
1929 return false;
1932 return del_on_close;