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/>.
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
)
39 p
= ntvfs_handle_get_backend_data(h
, pvfs
->ntvfs
);
42 f
= talloc_get_type(p
, struct pvfs_file
);
49 cleanup a open directory handle
51 static int pvfs_dir_handle_destructor(struct pvfs_file_handle
*h
)
53 if (h
->have_opendb_entry
) {
56 const char *delete_path
= NULL
;
58 lck
= odb_lock(h
, h
->pvfs
->odb_context
, &h
->odb_locking_key
);
60 DEBUG(0,("Unable to lock opendb for close\n"));
64 status
= odb_close_file(lck
, h
, &delete_path
);
65 if (!NT_STATUS_IS_OK(status
)) {
66 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
67 h
->name
->full_name
, nt_errstr(status
)));
70 if (h
->name
->stream_name
== NULL
&& delete_path
) {
71 status
= pvfs_xattr_unlink_hook(h
->pvfs
, delete_path
);
72 if (!NT_STATUS_IS_OK(status
)) {
73 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
74 delete_path
, nt_errstr(status
)));
76 if (pvfs_sys_rmdir(h
->pvfs
, delete_path
) != 0) {
77 DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n",
78 delete_path
, strerror(errno
)));
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
);
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
,
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
)) {
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
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
);
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
)
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
;
169 static NTSTATUS
pvfs_open_directory(struct pvfs_state
*pvfs
,
170 struct ntvfs_request
*req
,
171 struct pvfs_filename
*name
,
175 struct ntvfs_handle
*h
;
177 uint32_t create_action
;
178 uint32_t access_mask
= io
->generic
.in
.access_mask
;
179 struct odb_lock
*lck
;
181 uint32_t create_options
;
182 uint32_t share_access
;
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
) {
193 return NT_STATUS_NOT_A_DIRECTORY
;
195 return NT_STATUS_FILE_IS_A_DIRECTORY
;
199 /* if the client says it must be a directory, and it isn't,
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
:
218 case NTCREATEX_DISP_OPEN
:
220 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
224 case NTCREATEX_DISP_CREATE
:
226 return NT_STATUS_OBJECT_NAME_COLLISION
;
230 case NTCREATEX_DISP_OVERWRITE_IF
:
231 case NTCREATEX_DISP_OVERWRITE
:
232 case NTCREATEX_DISP_SUPERSEDE
:
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
);
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
;
253 /* check the security descriptor */
254 status
= pvfs_access_check(pvfs
, req
, name
, &access_mask
);
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
);
269 f
->pending_list
= NULL
;
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
;
278 f
->handle
->pvfs
= pvfs
;
279 f
->handle
->name
= talloc_steal(f
->handle
, name
);
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;
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
)) {
295 del_on_close
= false;
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
)) {
305 /* get a lock on this file before the actual open */
306 lck
= odb_lock(req
, pvfs
->odb_context
, &f
->handle
->odb_locking_key
);
308 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
310 /* we were supposed to do a blocking lock, so something
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
)) {
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
)) {
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
);
344 uint32_t attrib
= io
->generic
.in
.file_attr
| FILE_ATTRIBUTE_DIRECTORY
;
345 mode_t mode
= pvfs_fileperms(pvfs
, attrib
);
347 if (pvfs_sys_mkdir(pvfs
, name
->full_name
, mode
) == -1) {
348 return pvfs_map_errno(pvfs
,errno
);
351 pvfs_xattr_unlink_hook(pvfs
, name
->full_name
);
353 status
= pvfs_resolve_name(pvfs
, req
, io
->ntcreatex
.in
.fname
, 0, &name
);
354 if (!NT_STATUS_IS_OK(status
)) {
358 status
= pvfs_open_setup_eas_acl(pvfs
, req
, name
, -1, f
, io
, sd
);
359 if (!NT_STATUS_IS_OK(status
)) {
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
)) {
369 lck
= odb_lock(req
, pvfs
->odb_context
, &f
->handle
->odb_locking_key
);
371 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
373 /* we were supposed to do a blocking lock, so something
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
)) {
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
)) {
394 f
->handle
->have_opendb_entry
= true;
396 create_action
= NTCREATEX_ACTION_CREATED
;
398 notify_trigger(pvfs
->notify_context
,
400 FILE_NOTIFY_CHANGE_DIR_NAME
,
403 create_action
= NTCREATEX_ACTION_EXISTED
;
407 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
410 /* the open succeeded, keep this handle permanently */
411 status
= ntvfs_handle_set_backend_data(h
, pvfs
->ntvfs
, f
);
412 if (!NT_STATUS_IS_OK(status
)) {
416 f
->handle
->open_completed
= true;
418 io
->generic
.out
.oplock_level
= OPLOCK_NONE
;
419 io
->generic
.out
.file
.ntvfs
= h
;
420 io
->generic
.out
.create_action
= create_action
;
421 io
->generic
.out
.create_time
= name
->dos
.create_time
;
422 io
->generic
.out
.access_time
= name
->dos
.access_time
;
423 io
->generic
.out
.write_time
= name
->dos
.write_time
;
424 io
->generic
.out
.change_time
= name
->dos
.change_time
;
425 io
->generic
.out
.attrib
= name
->dos
.attrib
;
426 io
->generic
.out
.alloc_size
= name
->dos
.alloc_size
;
427 io
->generic
.out
.size
= name
->st
.st_size
;
428 io
->generic
.out
.file_type
= FILE_TYPE_DISK
;
429 io
->generic
.out
.ipc_state
= 0;
430 io
->generic
.out
.is_directory
= 1;
435 pvfs_sys_rmdir(pvfs
, name
->full_name
);
440 destroy a struct pvfs_file_handle
442 static int pvfs_handle_destructor(struct pvfs_file_handle
*h
)
444 talloc_free(h
->write_time
.update_event
);
445 h
->write_time
.update_event
= NULL
;
447 if ((h
->create_options
& NTCREATEX_OPTIONS_DELETE_ON_CLOSE
) &&
448 h
->name
->stream_name
) {
450 status
= pvfs_stream_delete(h
->pvfs
, h
->name
, h
->fd
);
451 if (!NT_STATUS_IS_OK(status
)) {
452 DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n",
453 h
->name
->stream_name
, h
->name
->full_name
));
458 if (close(h
->fd
) != 0) {
459 DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n",
460 h
->fd
, h
->name
->full_name
, strerror(errno
)));
465 if (!h
->write_time
.update_forced
&&
466 h
->write_time
.update_on_close
&&
467 h
->write_time
.close_time
== 0) {
469 tv
= timeval_current();
470 h
->write_time
.close_time
= timeval_to_nttime(&tv
);
473 if (h
->have_opendb_entry
) {
474 struct odb_lock
*lck
;
476 const char *delete_path
= NULL
;
478 lck
= odb_lock(h
, h
->pvfs
->odb_context
, &h
->odb_locking_key
);
480 DEBUG(0,("Unable to lock opendb for close\n"));
484 if (h
->write_time
.update_forced
) {
485 status
= odb_get_file_infos(h
->pvfs
->odb_context
,
488 &h
->write_time
.close_time
);
489 if (!NT_STATUS_IS_OK(status
)) {
490 DEBUG(0,("Unable get write time for '%s' - %s\n",
491 h
->name
->full_name
, nt_errstr(status
)));
494 h
->write_time
.update_forced
= false;
495 h
->write_time
.update_on_close
= true;
496 } else if (h
->write_time
.update_on_close
) {
497 status
= odb_set_write_time(lck
, h
->write_time
.close_time
, true);
498 if (!NT_STATUS_IS_OK(status
)) {
499 DEBUG(0,("Unable set write time for '%s' - %s\n",
500 h
->name
->full_name
, nt_errstr(status
)));
504 status
= odb_close_file(lck
, h
, &delete_path
);
505 if (!NT_STATUS_IS_OK(status
)) {
506 DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n",
507 h
->name
->full_name
, nt_errstr(status
)));
510 if (h
->name
->stream_name
== NULL
&&
511 h
->open_completed
&& delete_path
) {
512 status
= pvfs_xattr_unlink_hook(h
->pvfs
, delete_path
);
513 if (!NT_STATUS_IS_OK(status
)) {
514 DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n",
515 delete_path
, nt_errstr(status
)));
517 if (pvfs_sys_unlink(h
->pvfs
, delete_path
) != 0) {
518 DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n",
519 delete_path
, strerror(errno
)));
521 notify_trigger(h
->pvfs
->notify_context
,
522 NOTIFY_ACTION_REMOVED
,
523 FILE_NOTIFY_CHANGE_FILE_NAME
,
526 h
->write_time
.update_on_close
= false;
532 if (h
->write_time
.update_on_close
) {
533 struct timeval tv
[2];
535 nttime_to_timeval(&tv
[0], h
->name
->dos
.access_time
);
536 nttime_to_timeval(&tv
[1], h
->write_time
.close_time
);
538 if (!timeval_is_zero(&tv
[0]) || !timeval_is_zero(&tv
[1])) {
539 if (utimes(h
->name
->full_name
, tv
) == -1) {
540 DEBUG(3,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
541 h
->name
->full_name
, strerror(errno
)));
551 destroy a struct pvfs_file
553 static int pvfs_fnum_destructor(struct pvfs_file
*f
)
555 DLIST_REMOVE(f
->pvfs
->files
.list
, f
);
556 pvfs_lock_close(f
->pvfs
, f
);
557 ntvfs_handle_remove_backend_data(f
->ntvfs
, f
->pvfs
->ntvfs
);
564 form the lock context used for byte range locking. This is separate
565 from the locking key used for opendb locking as it needs to take
566 account of file streams (each stream is a separate byte range
569 static NTSTATUS
pvfs_brl_locking_handle(TALLOC_CTX
*mem_ctx
,
570 struct pvfs_filename
*name
,
571 struct ntvfs_handle
*ntvfs
,
572 struct brl_handle
**_h
)
574 DATA_BLOB odb_key
, key
;
576 struct brl_handle
*h
;
578 status
= pvfs_locking_key(name
, mem_ctx
, &odb_key
);
579 NT_STATUS_NOT_OK_RETURN(status
);
581 if (name
->stream_name
== NULL
) {
584 key
= data_blob_talloc(mem_ctx
, NULL
,
585 odb_key
.length
+ strlen(name
->stream_name
) + 1);
586 NT_STATUS_HAVE_NO_MEMORY(key
.data
);
587 memcpy(key
.data
, odb_key
.data
, odb_key
.length
);
588 memcpy(key
.data
+ odb_key
.length
,
589 name
->stream_name
, strlen(name
->stream_name
) + 1);
590 data_blob_free(&odb_key
);
593 h
= brl_create_handle(mem_ctx
, ntvfs
, &key
);
594 NT_STATUS_HAVE_NO_MEMORY(h
);
603 static NTSTATUS
pvfs_create_file(struct pvfs_state
*pvfs
,
604 struct ntvfs_request
*req
,
605 struct pvfs_filename
*name
,
610 struct ntvfs_handle
*h
;
612 struct odb_lock
*lck
;
613 uint32_t create_options
= io
->generic
.in
.create_options
;
614 uint32_t share_access
= io
->generic
.in
.share_access
;
615 uint32_t access_mask
= io
->generic
.in
.access_mask
;
619 struct pvfs_filename
*parent
;
620 uint32_t oplock_level
= OPLOCK_NONE
, oplock_granted
;
621 bool allow_level_II_oplock
= false;
622 struct security_descriptor
*sd
= NULL
;
624 if (io
->ntcreatex
.in
.file_attr
& ~FILE_ATTRIBUTE_ALL_MASK
) {
625 DEBUG(3,(__location__
": Invalid file_attr 0x%08x for %s\n",
626 io
->ntcreatex
.in
.file_attr
, name
->original_name
));
627 return NT_STATUS_INVALID_PARAMETER
;
630 if (io
->ntcreatex
.in
.file_attr
& FILE_ATTRIBUTE_ENCRYPTED
) {
631 DEBUG(3,(__location__
": Invalid encryption request for %s\n",
632 name
->original_name
));
633 return NT_STATUS_ACCESS_DENIED
;
636 if ((io
->ntcreatex
.in
.file_attr
& FILE_ATTRIBUTE_READONLY
) &&
637 (create_options
& NTCREATEX_OPTIONS_DELETE_ON_CLOSE
)) {
638 DEBUG(4,(__location__
": Invalid delete on close for readonly file %s\n",
639 name
->original_name
));
640 return NT_STATUS_CANNOT_DELETE
;
643 sd
= io
->ntcreatex
.in
.sec_desc
;
644 status
= pvfs_access_check_create(pvfs
, req
, name
, &access_mask
, false, &sd
);
645 NT_STATUS_NOT_OK_RETURN(status
);
647 /* check that the parent isn't opened with delete on close set */
648 status
= pvfs_resolve_parent(pvfs
, req
, name
, &parent
);
649 if (NT_STATUS_IS_OK(status
)) {
650 DATA_BLOB locking_key
;
651 status
= pvfs_locking_key(parent
, req
, &locking_key
);
652 NT_STATUS_NOT_OK_RETURN(status
);
653 status
= odb_get_file_infos(pvfs
->odb_context
, &locking_key
,
654 &del_on_close
, NULL
);
655 NT_STATUS_NOT_OK_RETURN(status
);
657 return NT_STATUS_DELETE_PENDING
;
661 if (access_mask
& (SEC_FILE_WRITE_DATA
| SEC_FILE_APPEND_DATA
)) {
667 status
= ntvfs_handle_new(pvfs
->ntvfs
, req
, &h
);
668 NT_STATUS_NOT_OK_RETURN(status
);
670 f
= talloc(h
, struct pvfs_file
);
671 NT_STATUS_HAVE_NO_MEMORY(f
);
673 f
->handle
= talloc(f
, struct pvfs_file_handle
);
674 NT_STATUS_HAVE_NO_MEMORY(f
->handle
);
676 attrib
= io
->ntcreatex
.in
.file_attr
| FILE_ATTRIBUTE_ARCHIVE
;
677 mode
= pvfs_fileperms(pvfs
, attrib
);
679 /* create the file */
680 fd
= pvfs_sys_open(pvfs
, name
->full_name
, flags
| O_CREAT
| O_EXCL
| O_NONBLOCK
, mode
);
682 return pvfs_map_errno(pvfs
, errno
);
685 pvfs_xattr_unlink_hook(pvfs
, name
->full_name
);
687 /* if this was a stream create then create the stream as well */
688 if (name
->stream_name
) {
689 status
= pvfs_stream_create(pvfs
, name
, fd
);
690 if (!NT_STATUS_IS_OK(status
)) {
696 /* re-resolve the open fd */
697 status
= pvfs_resolve_name_fd(pvfs
, fd
, name
, 0);
698 if (!NT_STATUS_IS_OK(status
)) {
703 /* support initial alloc sizes */
704 name
->dos
.alloc_size
= io
->ntcreatex
.in
.alloc_size
;
705 name
->dos
.attrib
= attrib
;
706 status
= pvfs_dosattrib_save(pvfs
, name
, fd
);
707 if (!NT_STATUS_IS_OK(status
)) {
712 status
= pvfs_open_setup_eas_acl(pvfs
, req
, name
, fd
, f
, io
, sd
);
713 if (!NT_STATUS_IS_OK(status
)) {
717 if (io
->generic
.in
.query_maximal_access
) {
718 status
= pvfs_access_maximal_allowed(pvfs
, req
, name
,
719 &io
->generic
.out
.maximal_access
);
720 NT_STATUS_NOT_OK_RETURN(status
);
723 /* form the lock context used for byte range locking and
725 status
= pvfs_locking_key(name
, f
->handle
, &f
->handle
->odb_locking_key
);
726 if (!NT_STATUS_IS_OK(status
)) {
730 status
= pvfs_brl_locking_handle(f
, name
, h
, &f
->brl_handle
);
731 if (!NT_STATUS_IS_OK(status
)) {
735 /* grab a lock on the open file record */
736 lck
= odb_lock(req
, pvfs
->odb_context
, &f
->handle
->odb_locking_key
);
738 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
740 /* we were supposed to do a blocking lock, so something
742 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
746 if (create_options
& NTCREATEX_OPTIONS_DELETE_ON_CLOSE
) {
749 del_on_close
= false;
752 if (pvfs
->flags
& PVFS_FLAG_FAKE_OPLOCKS
) {
753 oplock_level
= OPLOCK_NONE
;
754 } else if (io
->ntcreatex
.in
.flags
& NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
) {
755 oplock_level
= OPLOCK_BATCH
;
756 } else if (io
->ntcreatex
.in
.flags
& NTCREATEX_FLAGS_REQUEST_OPLOCK
) {
757 oplock_level
= OPLOCK_EXCLUSIVE
;
760 if (req
->client_caps
& NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS
) {
761 allow_level_II_oplock
= true;
764 status
= odb_can_open(lck
, name
->stream_id
,
765 share_access
, access_mask
, del_on_close
,
766 io
->generic
.in
.open_disposition
, false);
767 if (!NT_STATUS_IS_OK(status
)) {
769 /* bad news, we must have hit a race - we don't delete the file
770 here as the most likely scenario is that someone else created
771 the file at the same time */
778 f
->pending_list
= NULL
;
780 f
->share_access
= io
->generic
.in
.share_access
;
781 f
->access_mask
= access_mask
;
782 f
->impersonation
= io
->generic
.in
.impersonation
;
783 f
->notify_buffer
= NULL
;
786 f
->handle
->pvfs
= pvfs
;
787 f
->handle
->name
= talloc_steal(f
->handle
, name
);
789 f
->handle
->create_options
= io
->generic
.in
.create_options
;
790 f
->handle
->private_flags
= io
->generic
.in
.private_flags
;
791 f
->handle
->seek_offset
= 0;
792 f
->handle
->position
= 0;
794 f
->handle
->oplock
= NULL
;
795 f
->handle
->have_opendb_entry
= true;
796 ZERO_STRUCT(f
->handle
->write_time
);
797 f
->handle
->open_completed
= false;
799 status
= odb_open_file(lck
, f
->handle
, name
->full_name
,
800 &f
->handle
->fd
, name
->dos
.write_time
,
801 allow_level_II_oplock
,
802 oplock_level
, &oplock_granted
);
804 if (!NT_STATUS_IS_OK(status
)) {
805 /* bad news, we must have hit a race - we don't delete the file
806 here as the most likely scenario is that someone else created
807 the file at the same time */
812 DLIST_ADD(pvfs
->files
.list
, f
);
814 /* setup a destructor to avoid file descriptor leaks on
815 abnormal termination */
816 talloc_set_destructor(f
, pvfs_fnum_destructor
);
817 talloc_set_destructor(f
->handle
, pvfs_handle_destructor
);
819 if (pvfs
->flags
& PVFS_FLAG_FAKE_OPLOCKS
) {
820 oplock_granted
= OPLOCK_BATCH
;
821 } else if (oplock_granted
!= OPLOCK_NONE
) {
822 status
= pvfs_setup_oplock(f
, oplock_granted
);
823 if (!NT_STATUS_IS_OK(status
)) {
828 io
->generic
.out
.oplock_level
= oplock_granted
;
829 io
->generic
.out
.file
.ntvfs
= f
->ntvfs
;
830 io
->generic
.out
.create_action
= NTCREATEX_ACTION_CREATED
;
831 io
->generic
.out
.create_time
= name
->dos
.create_time
;
832 io
->generic
.out
.access_time
= name
->dos
.access_time
;
833 io
->generic
.out
.write_time
= name
->dos
.write_time
;
834 io
->generic
.out
.change_time
= name
->dos
.change_time
;
835 io
->generic
.out
.attrib
= name
->dos
.attrib
;
836 io
->generic
.out
.alloc_size
= name
->dos
.alloc_size
;
837 io
->generic
.out
.size
= name
->st
.st_size
;
838 io
->generic
.out
.file_type
= FILE_TYPE_DISK
;
839 io
->generic
.out
.ipc_state
= 0;
840 io
->generic
.out
.is_directory
= 0;
842 /* success - keep the file handle */
843 status
= ntvfs_handle_set_backend_data(h
, pvfs
->ntvfs
, f
);
844 if (!NT_STATUS_IS_OK(status
)) {
848 f
->handle
->open_completed
= true;
850 notify_trigger(pvfs
->notify_context
,
852 FILE_NOTIFY_CHANGE_FILE_NAME
,
859 pvfs_sys_unlink(pvfs
, name
->full_name
);
864 state of a pending retry
866 struct pvfs_odb_retry
{
867 struct ntvfs_module_context
*ntvfs
;
868 struct ntvfs_request
*req
;
869 DATA_BLOB odb_locking_key
;
872 void (*callback
)(struct pvfs_odb_retry
*r
,
873 struct ntvfs_module_context
*ntvfs
,
874 struct ntvfs_request
*req
,
877 enum pvfs_wait_notice reason
);
880 /* destroy a pending request */
881 static int pvfs_odb_retry_destructor(struct pvfs_odb_retry
*r
)
883 struct pvfs_state
*pvfs
= talloc_get_type(r
->ntvfs
->private_data
,
885 if (r
->odb_locking_key
.data
) {
886 struct odb_lock
*lck
;
887 lck
= odb_lock(r
->req
, pvfs
->odb_context
, &r
->odb_locking_key
);
889 odb_remove_pending(lck
, r
);
896 static void pvfs_odb_retry_callback(void *_r
, enum pvfs_wait_notice reason
)
898 struct pvfs_odb_retry
*r
= talloc_get_type(_r
, struct pvfs_odb_retry
);
900 if (reason
== PVFS_WAIT_EVENT
) {
902 * The pending odb entry is already removed.
903 * We use a null locking key to indicate this
906 data_blob_free(&r
->odb_locking_key
);
909 r
->callback(r
, r
->ntvfs
, r
->req
, r
->io
, r
->private_data
, reason
);
913 setup for a retry of a request that was rejected
916 NTSTATUS
pvfs_odb_retry_setup(struct ntvfs_module_context
*ntvfs
,
917 struct ntvfs_request
*req
,
918 struct odb_lock
*lck
,
919 struct timeval end_time
,
922 void (*callback
)(struct pvfs_odb_retry
*r
,
923 struct ntvfs_module_context
*ntvfs
,
924 struct ntvfs_request
*req
,
927 enum pvfs_wait_notice reason
))
929 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
931 struct pvfs_odb_retry
*r
;
932 struct pvfs_wait
*wait_handle
;
935 r
= talloc(req
, struct pvfs_odb_retry
);
936 NT_STATUS_HAVE_NO_MEMORY(r
);
941 r
->private_data
= private_data
;
942 r
->callback
= callback
;
943 r
->odb_locking_key
= odb_get_key(r
, lck
);
944 if (r
->odb_locking_key
.data
== NULL
) {
945 return NT_STATUS_NO_MEMORY
;
948 /* setup a pending lock */
949 status
= odb_open_file_pending(lck
, r
);
950 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND
,status
)) {
952 * maybe only a unix application
955 data_blob_free(&r
->odb_locking_key
);
956 } else if (!NT_STATUS_IS_OK(status
)) {
962 talloc_set_destructor(r
, pvfs_odb_retry_destructor
);
964 wait_handle
= pvfs_wait_message(pvfs
, req
,
965 MSG_PVFS_RETRY_OPEN
, end_time
,
966 pvfs_odb_retry_callback
, r
);
967 if (wait_handle
== NULL
) {
968 return NT_STATUS_NO_MEMORY
;
971 talloc_steal(r
, wait_handle
);
977 retry an open after a sharing violation
979 static void pvfs_retry_open_sharing(struct pvfs_odb_retry
*r
,
980 struct ntvfs_module_context
*ntvfs
,
981 struct ntvfs_request
*req
,
984 enum pvfs_wait_notice reason
)
986 union smb_open
*io
= talloc_get_type(_io
, union smb_open
);
987 struct timeval
*final_timeout
= NULL
;
991 final_timeout
= talloc_get_type(private_data
,
995 /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
996 just a bug in their server, but we better do the same */
997 if (reason
== PVFS_WAIT_CANCEL
) {
1001 if (reason
== PVFS_WAIT_TIMEOUT
) {
1002 if (final_timeout
&&
1003 !timeval_expired(final_timeout
)) {
1005 * we need to retry periodictly
1006 * after an EAGAIN as there's
1007 * no way the kernel tell us
1008 * an oplock is released.
1012 /* if it timed out, then give the failure
1015 req
->async_states
->status
= NT_STATUS_SHARING_VIOLATION
;
1016 req
->async_states
->send_fn(req
);
1023 /* try the open again, which could trigger another retry setup
1024 if it wants to, so we have to unmark the async flag so we
1025 will know if it does a second async reply */
1026 req
->async_states
->state
&= ~NTVFS_ASYNC_STATE_ASYNC
;
1028 status
= pvfs_open(ntvfs
, req
, io
);
1029 if (req
->async_states
->state
& NTVFS_ASYNC_STATE_ASYNC
) {
1030 /* the 2nd try also replied async, so we don't send
1035 /* re-mark it async, just in case someone up the chain does
1036 paranoid checking */
1037 req
->async_states
->state
|= NTVFS_ASYNC_STATE_ASYNC
;
1039 /* send the reply up the chain */
1040 req
->async_states
->status
= status
;
1041 req
->async_states
->send_fn(req
);
1046 special handling for openx DENY_DOS semantics
1048 This function attempts a reference open using an existing handle. If its allowed,
1049 then it returns NT_STATUS_OK, otherwise it returns any other code and normal
1050 open processing continues.
1052 static NTSTATUS
pvfs_open_deny_dos(struct ntvfs_module_context
*ntvfs
,
1053 struct ntvfs_request
*req
, union smb_open
*io
,
1054 struct pvfs_file
*f
, struct odb_lock
*lck
)
1056 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
1058 struct pvfs_file
*f2
;
1059 struct pvfs_filename
*name
;
1062 /* search for an existing open with the right parameters. Note
1063 the magic ntcreatex options flag, which is set in the
1064 generic mapping code. This might look ugly, but its
1065 actually pretty much now w2k does it internally as well.
1067 If you look at the BASE-DENYDOS test you will see that a
1068 DENY_DOS is a very special case, and in the right
1069 circumstances you actually get the _same_ handle back
1070 twice, rather than a new handle.
1072 for (f2
=pvfs
->files
.list
;f2
;f2
=f2
->next
) {
1074 f2
->ntvfs
->session_info
== req
->session_info
&&
1075 f2
->ntvfs
->smbpid
== req
->smbpid
&&
1076 (f2
->handle
->private_flags
&
1077 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS
|
1078 NTCREATEX_OPTIONS_PRIVATE_DENY_FCB
)) &&
1079 (f2
->access_mask
& SEC_FILE_WRITE_DATA
) &&
1080 strcasecmp_m(f2
->handle
->name
->original_name
,
1081 io
->generic
.in
.fname
)==0) {
1087 return NT_STATUS_SHARING_VIOLATION
;
1090 /* quite an insane set of semantics ... */
1091 if (is_exe_filename(io
->generic
.in
.fname
) &&
1092 (f2
->handle
->private_flags
& NTCREATEX_OPTIONS_PRIVATE_DENY_DOS
)) {
1093 return NT_STATUS_SHARING_VIOLATION
;
1097 setup a reference to the existing handle
1099 talloc_free(f
->handle
);
1100 f
->handle
= talloc_reference(f
, f2
->handle
);
1104 name
= f
->handle
->name
;
1106 io
->generic
.out
.oplock_level
= OPLOCK_NONE
;
1107 io
->generic
.out
.file
.ntvfs
= f
->ntvfs
;
1108 io
->generic
.out
.create_action
= NTCREATEX_ACTION_EXISTED
;
1109 io
->generic
.out
.create_time
= name
->dos
.create_time
;
1110 io
->generic
.out
.access_time
= name
->dos
.access_time
;
1111 io
->generic
.out
.write_time
= name
->dos
.write_time
;
1112 io
->generic
.out
.change_time
= name
->dos
.change_time
;
1113 io
->generic
.out
.attrib
= name
->dos
.attrib
;
1114 io
->generic
.out
.alloc_size
= name
->dos
.alloc_size
;
1115 io
->generic
.out
.size
= name
->st
.st_size
;
1116 io
->generic
.out
.file_type
= FILE_TYPE_DISK
;
1117 io
->generic
.out
.ipc_state
= 0;
1118 io
->generic
.out
.is_directory
= 0;
1120 status
= ntvfs_handle_set_backend_data(f
->ntvfs
, ntvfs
, f
);
1121 NT_STATUS_NOT_OK_RETURN(status
);
1123 return NT_STATUS_OK
;
1129 setup for a open retry after a sharing violation
1131 static NTSTATUS
pvfs_open_setup_retry(struct ntvfs_module_context
*ntvfs
,
1132 struct ntvfs_request
*req
,
1134 struct pvfs_file
*f
,
1135 struct odb_lock
*lck
,
1136 NTSTATUS parent_status
)
1138 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
1141 struct timeval end_time
;
1142 struct timeval
*final_timeout
= NULL
;
1144 if (io
->generic
.in
.private_flags
&
1145 (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS
| NTCREATEX_OPTIONS_PRIVATE_DENY_FCB
)) {
1146 /* see if we can satisfy the request using the special DENY_DOS
1148 status
= pvfs_open_deny_dos(ntvfs
, req
, io
, f
, lck
);
1149 if (NT_STATUS_IS_OK(status
)) {
1154 /* the retry should allocate a new file handle */
1157 if (NT_STATUS_EQUAL(parent_status
, NT_STATUS_SHARING_VIOLATION
)) {
1158 end_time
= timeval_add(&req
->statistics
.request_time
,
1159 0, pvfs
->sharing_violation_delay
);
1160 } else if (NT_STATUS_EQUAL(parent_status
, NT_STATUS_OPLOCK_NOT_GRANTED
)) {
1161 end_time
= timeval_add(&req
->statistics
.request_time
,
1162 pvfs
->oplock_break_timeout
, 0);
1163 } else if (NT_STATUS_EQUAL(parent_status
, STATUS_MORE_ENTRIES
)) {
1165 * we got EAGAIN which means a unix application
1166 * has an oplock or share mode
1168 * we retry every 4/5 of the sharing violation delay
1169 * to see if the unix application
1170 * has released the oplock or share mode.
1172 final_timeout
= talloc(req
, struct timeval
);
1173 NT_STATUS_HAVE_NO_MEMORY(final_timeout
);
1174 *final_timeout
= timeval_add(&req
->statistics
.request_time
,
1175 pvfs
->oplock_break_timeout
,
1177 end_time
= timeval_current_ofs(0, (pvfs
->sharing_violation_delay
*4)/5);
1178 end_time
= timeval_min(final_timeout
, &end_time
);
1180 return NT_STATUS_INTERNAL_ERROR
;
1183 return pvfs_odb_retry_setup(ntvfs
, req
, lck
, end_time
, io
,
1184 final_timeout
, pvfs_retry_open_sharing
);
1190 NTSTATUS
pvfs_open(struct ntvfs_module_context
*ntvfs
,
1191 struct ntvfs_request
*req
, union smb_open
*io
)
1193 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
1196 struct pvfs_filename
*name
;
1197 struct pvfs_file
*f
;
1198 struct ntvfs_handle
*h
;
1201 struct odb_lock
*lck
;
1202 uint32_t create_options
;
1203 uint32_t create_options_must_ignore_mask
;
1204 uint32_t share_access
;
1205 uint32_t access_mask
;
1206 uint32_t create_action
= NTCREATEX_ACTION_EXISTED
;
1208 bool stream_existed
, stream_truncate
=false;
1209 uint32_t oplock_level
= OPLOCK_NONE
, oplock_granted
;
1210 bool allow_level_II_oplock
= false;
1212 /* use the generic mapping code to avoid implementing all the
1213 different open calls. */
1214 if (io
->generic
.level
!= RAW_OPEN_GENERIC
&&
1215 io
->generic
.level
!= RAW_OPEN_NTTRANS_CREATE
) {
1216 return ntvfs_map_open(ntvfs
, req
, io
);
1219 ZERO_STRUCT(io
->generic
.out
);
1221 create_options
= io
->generic
.in
.create_options
;
1222 share_access
= io
->generic
.in
.share_access
;
1223 access_mask
= io
->generic
.in
.access_mask
;
1225 if (share_access
& ~NTCREATEX_SHARE_ACCESS_MASK
) {
1226 DEBUG(3,(__location__
": Invalid share_access 0x%08x for %s\n",
1227 share_access
, io
->ntcreatex
.in
.fname
));
1228 return NT_STATUS_INVALID_PARAMETER
;
1232 * These options are ignored,
1233 * but we reuse some of them as private values for the generic mapping
1235 create_options_must_ignore_mask
= NTCREATEX_OPTIONS_MUST_IGNORE_MASK
;
1236 create_options
&= ~create_options_must_ignore_mask
;
1238 if (create_options
& NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK
) {
1239 DEBUG(2,(__location__
" create_options 0x%x not supported\n",
1241 return NT_STATUS_NOT_SUPPORTED
;
1244 if (create_options
& NTCREATEX_OPTIONS_INVALID_PARAM_MASK
) {
1245 DEBUG(3,(__location__
": Invalid create_options 0x%08x for %s\n",
1246 create_options
, io
->ntcreatex
.in
.fname
));
1247 return NT_STATUS_INVALID_PARAMETER
;
1250 /* TODO: When we implement HSM, add a hook here not to pull
1251 * the actual file off tape, when this option is passed from
1253 if (create_options
& NTCREATEX_OPTIONS_NO_RECALL
) {
1257 /* TODO: If (unlikely) Linux does a good compressed
1258 * filesystem, we might need an ioctl call for this */
1259 if (create_options
& NTCREATEX_OPTIONS_NO_COMPRESSION
) {
1263 if (create_options
& NTCREATEX_OPTIONS_NO_INTERMEDIATE_BUFFERING
) {
1264 create_options
|= NTCREATEX_OPTIONS_WRITE_THROUGH
;
1267 /* Open the file with sync, if they asked for it, but
1268 'strict sync = no' turns this client request into a no-op */
1269 if (create_options
& (NTCREATEX_OPTIONS_WRITE_THROUGH
) && !(pvfs
->flags
| PVFS_FLAG_STRICT_SYNC
)) {
1274 /* other create options are not allowed */
1275 if ((create_options
& NTCREATEX_OPTIONS_DELETE_ON_CLOSE
) &&
1276 !(access_mask
& SEC_STD_DELETE
)) {
1277 DEBUG(3,(__location__
": Invalid delete_on_close option 0x%08x with access_mask 0x%08x for %s\n",
1278 create_options
, access_mask
, io
->ntcreatex
.in
.fname
));
1279 return NT_STATUS_INVALID_PARAMETER
;
1282 if (access_mask
& SEC_MASK_INVALID
) {
1283 return NT_STATUS_ACCESS_DENIED
;
1286 /* what does this bit really mean?? */
1287 if (req
->ctx
->protocol
== PROTOCOL_SMB2
&&
1288 access_mask
== SEC_STD_SYNCHRONIZE
) {
1289 return NT_STATUS_ACCESS_DENIED
;
1292 /* cope with non-zero root_fid */
1293 if (io
->ntcreatex
.in
.root_fid
.ntvfs
!= NULL
) {
1294 f
= pvfs_find_fd(pvfs
, req
, io
->ntcreatex
.in
.root_fid
.ntvfs
);
1296 return NT_STATUS_INVALID_HANDLE
;
1298 if (f
->handle
->fd
!= -1) {
1299 return NT_STATUS_INVALID_DEVICE_REQUEST
;
1301 io
->ntcreatex
.in
.fname
= talloc_asprintf(req
, "%s\\%s",
1302 f
->handle
->name
->original_name
,
1303 io
->ntcreatex
.in
.fname
);
1304 NT_STATUS_HAVE_NO_MEMORY(io
->ntcreatex
.in
.fname
);
1307 if (io
->ntcreatex
.in
.file_attr
& (FILE_ATTRIBUTE_DEVICE
|
1308 FILE_ATTRIBUTE_VOLUME
|
1309 (~FILE_ATTRIBUTE_ALL_MASK
))) {
1310 DEBUG(3,(__location__
": Invalid file_attr 0x%08x for %s\n",
1311 io
->ntcreatex
.in
.file_attr
, io
->ntcreatex
.in
.fname
));
1312 return NT_STATUS_INVALID_PARAMETER
;
1315 /* we ignore some file_attr bits */
1316 io
->ntcreatex
.in
.file_attr
&= ~(FILE_ATTRIBUTE_NONINDEXED
|
1317 FILE_ATTRIBUTE_COMPRESSED
|
1318 FILE_ATTRIBUTE_REPARSE_POINT
|
1319 FILE_ATTRIBUTE_SPARSE
|
1320 FILE_ATTRIBUTE_NORMAL
);
1322 /* resolve the cifs name to a posix name */
1323 status
= pvfs_resolve_name(pvfs
, req
, io
->ntcreatex
.in
.fname
,
1324 PVFS_RESOLVE_STREAMS
, &name
);
1325 if (!NT_STATUS_IS_OK(status
)) {
1329 /* if the client specified that it must not be a directory then
1330 check that it isn't */
1331 if (name
->exists
&& (name
->dos
.attrib
& FILE_ATTRIBUTE_DIRECTORY
) &&
1332 (io
->generic
.in
.create_options
& NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
)) {
1333 return NT_STATUS_FILE_IS_A_DIRECTORY
;
1336 /* if the client specified that it must be a directory then
1338 if (name
->exists
&& !(name
->dos
.attrib
& FILE_ATTRIBUTE_DIRECTORY
) &&
1339 (io
->generic
.in
.create_options
& NTCREATEX_OPTIONS_DIRECTORY
)) {
1340 return NT_STATUS_NOT_A_DIRECTORY
;
1343 /* directory opens are handled separately */
1344 if ((name
->exists
&& (name
->dos
.attrib
& FILE_ATTRIBUTE_DIRECTORY
)) ||
1345 (io
->generic
.in
.create_options
& NTCREATEX_OPTIONS_DIRECTORY
)) {
1346 return pvfs_open_directory(pvfs
, req
, name
, io
);
1349 /* FILE_ATTRIBUTE_DIRECTORY is ignored if the above test for directory
1350 open doesn't match */
1351 io
->generic
.in
.file_attr
&= ~FILE_ATTRIBUTE_DIRECTORY
;
1353 switch (io
->generic
.in
.open_disposition
) {
1354 case NTCREATEX_DISP_SUPERSEDE
:
1355 case NTCREATEX_DISP_OVERWRITE_IF
:
1356 if (name
->stream_name
== NULL
) {
1359 stream_truncate
= true;
1361 create_action
= NTCREATEX_ACTION_TRUNCATED
;
1364 case NTCREATEX_DISP_OPEN
:
1365 if (!name
->stream_exists
) {
1366 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1371 case NTCREATEX_DISP_OVERWRITE
:
1372 if (!name
->stream_exists
) {
1373 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1375 if (name
->stream_name
== NULL
) {
1378 stream_truncate
= true;
1380 create_action
= NTCREATEX_ACTION_TRUNCATED
;
1383 case NTCREATEX_DISP_CREATE
:
1384 if (name
->stream_exists
) {
1385 return NT_STATUS_OBJECT_NAME_COLLISION
;
1390 case NTCREATEX_DISP_OPEN_IF
:
1395 DEBUG(3,(__location__
": Invalid open disposition 0x%08x for %s\n",
1396 io
->generic
.in
.open_disposition
, name
->original_name
));
1397 return NT_STATUS_INVALID_PARAMETER
;
1400 /* handle creating a new file separately */
1401 if (!name
->exists
) {
1402 status
= pvfs_create_file(pvfs
, req
, name
, io
);
1403 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OBJECT_NAME_COLLISION
)) {
1407 /* we've hit a race - the file was created during this call */
1408 if (io
->generic
.in
.open_disposition
== NTCREATEX_DISP_CREATE
) {
1412 /* try re-resolving the name */
1413 status
= pvfs_resolve_name(pvfs
, req
, io
->ntcreatex
.in
.fname
, 0, &name
);
1414 if (!NT_STATUS_IS_OK(status
)) {
1417 /* fall through to a normal open */
1420 if ((name
->dos
.attrib
& FILE_ATTRIBUTE_READONLY
) &&
1421 (create_options
& NTCREATEX_OPTIONS_DELETE_ON_CLOSE
)) {
1422 return NT_STATUS_CANNOT_DELETE
;
1425 /* check the security descriptor */
1426 status
= pvfs_access_check(pvfs
, req
, name
, &access_mask
);
1427 NT_STATUS_NOT_OK_RETURN(status
);
1429 if (io
->generic
.in
.query_maximal_access
) {
1430 status
= pvfs_access_maximal_allowed(pvfs
, req
, name
,
1431 &io
->generic
.out
.maximal_access
);
1432 NT_STATUS_NOT_OK_RETURN(status
);
1435 status
= ntvfs_handle_new(pvfs
->ntvfs
, req
, &h
);
1436 NT_STATUS_NOT_OK_RETURN(status
);
1438 f
= talloc(h
, struct pvfs_file
);
1440 return NT_STATUS_NO_MEMORY
;
1443 f
->handle
= talloc(f
, struct pvfs_file_handle
);
1444 if (f
->handle
== NULL
) {
1445 return NT_STATUS_NO_MEMORY
;
1450 f
->pending_list
= NULL
;
1452 f
->share_access
= io
->generic
.in
.share_access
;
1453 f
->access_mask
= access_mask
;
1454 f
->impersonation
= io
->generic
.in
.impersonation
;
1455 f
->notify_buffer
= NULL
;
1458 f
->handle
->pvfs
= pvfs
;
1460 f
->handle
->name
= talloc_steal(f
->handle
, name
);
1461 f
->handle
->create_options
= io
->generic
.in
.create_options
;
1462 f
->handle
->private_flags
= io
->generic
.in
.private_flags
;
1463 f
->handle
->seek_offset
= 0;
1464 f
->handle
->position
= 0;
1465 f
->handle
->mode
= 0;
1466 f
->handle
->oplock
= NULL
;
1467 f
->handle
->have_opendb_entry
= false;
1468 ZERO_STRUCT(f
->handle
->write_time
);
1469 f
->handle
->open_completed
= false;
1471 /* form the lock context used for byte range locking and
1473 status
= pvfs_locking_key(name
, f
->handle
, &f
->handle
->odb_locking_key
);
1474 if (!NT_STATUS_IS_OK(status
)) {
1478 status
= pvfs_brl_locking_handle(f
, name
, h
, &f
->brl_handle
);
1479 if (!NT_STATUS_IS_OK(status
)) {
1483 /* get a lock on this file before the actual open */
1484 lck
= odb_lock(req
, pvfs
->odb_context
, &f
->handle
->odb_locking_key
);
1486 DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n",
1488 /* we were supposed to do a blocking lock, so something
1490 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1493 DLIST_ADD(pvfs
->files
.list
, f
);
1495 /* setup a destructor to avoid file descriptor leaks on
1496 abnormal termination */
1497 talloc_set_destructor(f
, pvfs_fnum_destructor
);
1498 talloc_set_destructor(f
->handle
, pvfs_handle_destructor
);
1501 * Only SMB2 takes care of the delete_on_close,
1504 if (create_options
& NTCREATEX_OPTIONS_DELETE_ON_CLOSE
&&
1505 req
->ctx
->protocol
== PROTOCOL_SMB2
) {
1506 del_on_close
= true;
1508 del_on_close
= false;
1511 if (pvfs
->flags
& PVFS_FLAG_FAKE_OPLOCKS
) {
1512 oplock_level
= OPLOCK_NONE
;
1513 } else if (io
->ntcreatex
.in
.flags
& NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
) {
1514 oplock_level
= OPLOCK_BATCH
;
1515 } else if (io
->ntcreatex
.in
.flags
& NTCREATEX_FLAGS_REQUEST_OPLOCK
) {
1516 oplock_level
= OPLOCK_EXCLUSIVE
;
1519 if (req
->client_caps
& NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS
) {
1520 allow_level_II_oplock
= true;
1523 /* see if we are allowed to open at the same time as existing opens */
1524 status
= odb_can_open(lck
, name
->stream_id
,
1525 share_access
, access_mask
, del_on_close
,
1526 io
->generic
.in
.open_disposition
, false);
1529 * on a sharing violation we need to retry when the file is closed by
1530 * the other user, or after 1 second
1531 * on a non granted oplock we need to retry when the file is closed by
1532 * the other user, or after 30 seconds
1534 if ((NT_STATUS_EQUAL(status
, NT_STATUS_SHARING_VIOLATION
) ||
1535 NT_STATUS_EQUAL(status
, NT_STATUS_OPLOCK_NOT_GRANTED
)) &&
1536 (req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1537 return pvfs_open_setup_retry(ntvfs
, req
, io
, f
, lck
, status
);
1540 if (!NT_STATUS_IS_OK(status
)) {
1545 if (access_mask
& (SEC_FILE_WRITE_DATA
| SEC_FILE_APPEND_DATA
)) {
1551 /* do the actual open */
1552 fd
= pvfs_sys_open(pvfs
, f
->handle
->name
->full_name
, flags
| O_NONBLOCK
, 0);
1554 status
= pvfs_map_errno(f
->pvfs
, errno
);
1556 DEBUG(0,(__location__
" mapped errno %s for %s (was %d)\n",
1557 nt_errstr(status
), f
->handle
->name
->full_name
, errno
));
1559 * STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
1561 if (NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
) &&
1562 (req
->async_states
->state
& NTVFS_ASYNC_STATE_MAY_ASYNC
)) {
1563 return pvfs_open_setup_retry(ntvfs
, req
, io
, f
, lck
, status
);
1572 status
= brl_count(f
->pvfs
->brl_context
, f
->brl_handle
, &count
);
1573 if (!NT_STATUS_IS_OK(status
)) {
1579 oplock_level
= OPLOCK_NONE
;
1582 /* now really mark the file as open */
1583 status
= odb_open_file(lck
, f
->handle
, name
->full_name
,
1584 &f
->handle
->fd
, name
->dos
.write_time
,
1585 allow_level_II_oplock
,
1586 oplock_level
, &oplock_granted
);
1588 if (!NT_STATUS_IS_OK(status
)) {
1593 f
->handle
->have_opendb_entry
= true;
1595 if (pvfs
->flags
& PVFS_FLAG_FAKE_OPLOCKS
) {
1596 oplock_granted
= OPLOCK_BATCH
;
1597 } else if (oplock_granted
!= OPLOCK_NONE
) {
1598 status
= pvfs_setup_oplock(f
, oplock_granted
);
1599 if (!NT_STATUS_IS_OK(status
)) {
1605 stream_existed
= name
->stream_exists
;
1607 /* if this was a stream create then create the stream as well */
1608 if (!name
->stream_exists
) {
1609 status
= pvfs_stream_create(pvfs
, f
->handle
->name
, fd
);
1610 if (!NT_STATUS_IS_OK(status
)) {
1614 if (stream_truncate
) {
1615 status
= pvfs_stream_truncate(pvfs
, f
->handle
->name
, fd
, 0);
1616 if (!NT_STATUS_IS_OK(status
)) {
1623 /* re-resolve the open fd */
1624 status
= pvfs_resolve_name_fd(f
->pvfs
, fd
, f
->handle
->name
, PVFS_RESOLVE_NO_OPENDB
);
1625 if (!NT_STATUS_IS_OK(status
)) {
1630 if (f
->handle
->name
->stream_id
== 0 &&
1631 (io
->generic
.in
.open_disposition
== NTCREATEX_DISP_OVERWRITE
||
1632 io
->generic
.in
.open_disposition
== NTCREATEX_DISP_OVERWRITE_IF
)) {
1633 /* for overwrite we may need to replace file permissions */
1634 uint32_t attrib
= io
->ntcreatex
.in
.file_attr
| FILE_ATTRIBUTE_ARCHIVE
;
1635 mode_t mode
= pvfs_fileperms(pvfs
, attrib
);
1636 if (f
->handle
->name
->st
.st_mode
!= mode
&&
1637 f
->handle
->name
->dos
.attrib
!= attrib
&&
1638 pvfs_sys_fchmod(pvfs
, fd
, mode
) == -1) {
1640 return pvfs_map_errno(pvfs
, errno
);
1642 name
->dos
.alloc_size
= io
->ntcreatex
.in
.alloc_size
;
1643 name
->dos
.attrib
= attrib
;
1644 status
= pvfs_dosattrib_save(pvfs
, name
, fd
);
1645 if (!NT_STATUS_IS_OK(status
)) {
1653 status
= ntvfs_handle_set_backend_data(h
, ntvfs
, f
);
1654 NT_STATUS_NOT_OK_RETURN(status
);
1656 /* mark the open as having completed fully, so delete on close
1658 f
->handle
->open_completed
= true;
1660 io
->generic
.out
.oplock_level
= oplock_granted
;
1661 io
->generic
.out
.file
.ntvfs
= h
;
1662 io
->generic
.out
.create_action
= stream_existed
?
1663 create_action
:NTCREATEX_ACTION_CREATED
;
1665 io
->generic
.out
.create_time
= name
->dos
.create_time
;
1666 io
->generic
.out
.access_time
= name
->dos
.access_time
;
1667 io
->generic
.out
.write_time
= name
->dos
.write_time
;
1668 io
->generic
.out
.change_time
= name
->dos
.change_time
;
1669 io
->generic
.out
.attrib
= name
->dos
.attrib
;
1670 io
->generic
.out
.alloc_size
= name
->dos
.alloc_size
;
1671 io
->generic
.out
.size
= name
->st
.st_size
;
1672 io
->generic
.out
.file_type
= FILE_TYPE_DISK
;
1673 io
->generic
.out
.ipc_state
= 0;
1674 io
->generic
.out
.is_directory
= 0;
1676 return NT_STATUS_OK
;
1683 NTSTATUS
pvfs_close(struct ntvfs_module_context
*ntvfs
,
1684 struct ntvfs_request
*req
, union smb_close
*io
)
1686 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
1688 struct pvfs_file
*f
;
1690 if (io
->generic
.level
== RAW_CLOSE_SPLCLOSE
) {
1691 return NT_STATUS_DOS(ERRSRV
, ERRerror
);
1694 if (io
->generic
.level
!= RAW_CLOSE_GENERIC
) {
1695 return ntvfs_map_close(ntvfs
, req
, io
);
1698 f
= pvfs_find_fd(pvfs
, req
, io
->generic
.in
.file
.ntvfs
);
1700 return NT_STATUS_INVALID_HANDLE
;
1703 if (!null_time(io
->generic
.in
.write_time
)) {
1704 f
->handle
->write_time
.update_forced
= false;
1705 f
->handle
->write_time
.update_on_close
= true;
1706 unix_to_nt_time(&f
->handle
->write_time
.close_time
, io
->generic
.in
.write_time
);
1709 if (io
->generic
.in
.flags
& SMB2_CLOSE_FLAGS_FULL_INFORMATION
) {
1710 struct pvfs_filename
*name
;
1712 struct pvfs_file_handle
*h
= f
->handle
;
1714 status
= pvfs_resolve_name_handle(pvfs
, h
);
1715 if (!NT_STATUS_IS_OK(status
)) {
1720 io
->generic
.out
.flags
= SMB2_CLOSE_FLAGS_FULL_INFORMATION
;
1721 io
->generic
.out
.create_time
= name
->dos
.create_time
;
1722 io
->generic
.out
.access_time
= name
->dos
.access_time
;
1723 io
->generic
.out
.write_time
= name
->dos
.write_time
;
1724 io
->generic
.out
.change_time
= name
->dos
.change_time
;
1725 io
->generic
.out
.alloc_size
= name
->dos
.alloc_size
;
1726 io
->generic
.out
.size
= name
->st
.st_size
;
1727 io
->generic
.out
.file_attr
= name
->dos
.attrib
;
1729 ZERO_STRUCT(io
->generic
.out
);
1734 return NT_STATUS_OK
;
1739 logoff - close all file descriptors open by a vuid
1741 NTSTATUS
pvfs_logoff(struct ntvfs_module_context
*ntvfs
,
1742 struct ntvfs_request
*req
)
1744 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
1746 struct pvfs_file
*f
, *next
;
1748 /* If pvfs is NULL, we never logged on, and no files are open. */
1750 return NT_STATUS_OK
;
1753 for (f
=pvfs
->files
.list
;f
;f
=next
) {
1755 if (f
->ntvfs
->session_info
== req
->session_info
) {
1760 return NT_STATUS_OK
;
1765 exit - close files for the current pid
1767 NTSTATUS
pvfs_exit(struct ntvfs_module_context
*ntvfs
,
1768 struct ntvfs_request
*req
)
1770 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
1772 struct pvfs_file
*f
, *next
;
1774 for (f
=pvfs
->files
.list
;f
;f
=next
) {
1776 if (f
->ntvfs
->session_info
== req
->session_info
&&
1777 f
->ntvfs
->smbpid
== req
->smbpid
) {
1782 return NT_STATUS_OK
;
1787 change the delete on close flag on an already open file
1789 NTSTATUS
pvfs_set_delete_on_close(struct pvfs_state
*pvfs
,
1790 struct ntvfs_request
*req
,
1791 struct pvfs_file
*f
, bool del_on_close
)
1793 struct odb_lock
*lck
;
1796 if ((f
->handle
->name
->dos
.attrib
& FILE_ATTRIBUTE_READONLY
) && del_on_close
) {
1797 return NT_STATUS_CANNOT_DELETE
;
1800 if ((f
->handle
->name
->dos
.attrib
& FILE_ATTRIBUTE_DIRECTORY
) &&
1801 !pvfs_directory_empty(pvfs
, f
->handle
->name
)) {
1802 return NT_STATUS_DIRECTORY_NOT_EMPTY
;
1806 f
->handle
->create_options
|= NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
1808 f
->handle
->create_options
&= ~NTCREATEX_OPTIONS_DELETE_ON_CLOSE
;
1811 lck
= odb_lock(req
, pvfs
->odb_context
, &f
->handle
->odb_locking_key
);
1813 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1816 status
= odb_set_delete_on_close(lck
, del_on_close
);
1825 determine if a file can be deleted, or if it is prevented by an
1828 NTSTATUS
pvfs_can_delete(struct pvfs_state
*pvfs
,
1829 struct ntvfs_request
*req
,
1830 struct pvfs_filename
*name
,
1831 struct odb_lock
**lckp
)
1835 struct odb_lock
*lck
;
1836 uint32_t share_access
;
1837 uint32_t access_mask
;
1838 bool delete_on_close
;
1840 status
= pvfs_locking_key(name
, name
, &key
);
1841 if (!NT_STATUS_IS_OK(status
)) {
1842 return NT_STATUS_NO_MEMORY
;
1845 lck
= odb_lock(req
, pvfs
->odb_context
, &key
);
1847 DEBUG(0,("Unable to lock opendb for can_delete\n"));
1848 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1851 share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1852 NTCREATEX_SHARE_ACCESS_WRITE
|
1853 NTCREATEX_SHARE_ACCESS_DELETE
;
1854 access_mask
= SEC_STD_DELETE
;
1855 delete_on_close
= true;
1857 status
= odb_can_open(lck
, name
->stream_id
,
1858 share_access
, access_mask
, delete_on_close
,
1859 NTCREATEX_DISP_OPEN
, false);
1861 if (NT_STATUS_IS_OK(status
)) {
1862 status
= pvfs_access_check_simple(pvfs
, req
, name
, access_mask
);
1866 * if it's a sharing violation or we got no oplock
1867 * only keep the lock if the caller requested access
1870 if (NT_STATUS_EQUAL(status
, NT_STATUS_SHARING_VIOLATION
) ||
1871 NT_STATUS_EQUAL(status
, NT_STATUS_OPLOCK_NOT_GRANTED
)) {
1877 } else if (!NT_STATUS_IS_OK(status
)) {
1890 determine if a file can be renamed, or if it is prevented by an
1893 NTSTATUS
pvfs_can_rename(struct pvfs_state
*pvfs
,
1894 struct ntvfs_request
*req
,
1895 struct pvfs_filename
*name
,
1896 struct odb_lock
**lckp
)
1900 struct odb_lock
*lck
;
1901 uint32_t share_access
;
1902 uint32_t access_mask
;
1903 bool delete_on_close
;
1905 status
= pvfs_locking_key(name
, name
, &key
);
1906 if (!NT_STATUS_IS_OK(status
)) {
1907 return NT_STATUS_NO_MEMORY
;
1910 lck
= odb_lock(req
, pvfs
->odb_context
, &key
);
1912 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1913 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1916 share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1917 NTCREATEX_SHARE_ACCESS_WRITE
;
1918 access_mask
= SEC_STD_DELETE
;
1919 delete_on_close
= false;
1921 status
= odb_can_open(lck
, name
->stream_id
,
1922 share_access
, access_mask
, delete_on_close
,
1923 NTCREATEX_DISP_OPEN
, false);
1926 * if it's a sharing violation or we got no oplock
1927 * only keep the lock if the caller requested access
1930 if (NT_STATUS_EQUAL(status
, NT_STATUS_SHARING_VIOLATION
) ||
1931 NT_STATUS_EQUAL(status
, NT_STATUS_OPLOCK_NOT_GRANTED
)) {
1937 } else if (!NT_STATUS_IS_OK(status
)) {
1950 determine if the file size of a file can be changed,
1951 or if it is prevented by an already open file
1953 NTSTATUS
pvfs_can_update_file_size(struct pvfs_state
*pvfs
,
1954 struct ntvfs_request
*req
,
1955 struct pvfs_filename
*name
,
1956 struct odb_lock
**lckp
)
1960 struct odb_lock
*lck
;
1961 uint32_t share_access
;
1962 uint32_t access_mask
;
1964 bool delete_on_close
;
1966 status
= pvfs_locking_key(name
, name
, &key
);
1967 if (!NT_STATUS_IS_OK(status
)) {
1968 return NT_STATUS_NO_MEMORY
;
1971 lck
= odb_lock(req
, pvfs
->odb_context
, &key
);
1973 DEBUG(0,("Unable to lock opendb for can_stat\n"));
1974 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1977 share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1978 NTCREATEX_SHARE_ACCESS_WRITE
|
1979 NTCREATEX_SHARE_ACCESS_DELETE
;
1981 * this code previous set only SEC_FILE_WRITE_ATTRIBUTE, with
1982 * a comment that this seemed to be wrong, but matched windows
1983 * behaviour. It now appears that this windows behaviour is
1986 access_mask
= SEC_FILE_WRITE_ATTRIBUTE
| SEC_FILE_WRITE_DATA
| SEC_FILE_APPEND_DATA
;
1987 delete_on_close
= false;
1988 break_to_none
= true;
1990 status
= odb_can_open(lck
, name
->stream_id
,
1991 share_access
, access_mask
, delete_on_close
,
1992 NTCREATEX_DISP_OPEN
, break_to_none
);
1995 * if it's a sharing violation or we got no oplock
1996 * only keep the lock if the caller requested access
1999 if (NT_STATUS_EQUAL(status
, NT_STATUS_SHARING_VIOLATION
) ||
2000 NT_STATUS_EQUAL(status
, NT_STATUS_OPLOCK_NOT_GRANTED
)) {
2006 } else if (!NT_STATUS_IS_OK(status
)) {
2019 determine if file meta data can be accessed, or if it is prevented by an
2022 NTSTATUS
pvfs_can_stat(struct pvfs_state
*pvfs
,
2023 struct ntvfs_request
*req
,
2024 struct pvfs_filename
*name
)
2028 struct odb_lock
*lck
;
2029 uint32_t share_access
;
2030 uint32_t access_mask
;
2031 bool delete_on_close
;
2033 status
= pvfs_locking_key(name
, name
, &key
);
2034 if (!NT_STATUS_IS_OK(status
)) {
2035 return NT_STATUS_NO_MEMORY
;
2038 lck
= odb_lock(req
, pvfs
->odb_context
, &key
);
2040 DEBUG(0,("Unable to lock opendb for can_stat\n"));
2041 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
2044 share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2045 NTCREATEX_SHARE_ACCESS_WRITE
;
2046 access_mask
= SEC_FILE_READ_ATTRIBUTE
;
2047 delete_on_close
= false;
2049 status
= odb_can_open(lck
, name
->stream_id
,
2050 share_access
, access_mask
, delete_on_close
,
2051 NTCREATEX_DISP_OPEN
, false);
2053 if (!NT_STATUS_IS_OK(status
)) {
2062 determine if delete on close is set on
2064 bool pvfs_delete_on_close_set(struct pvfs_state
*pvfs
, struct pvfs_file_handle
*h
)
2069 status
= odb_get_file_infos(pvfs
->odb_context
, &h
->odb_locking_key
,
2070 &del_on_close
, NULL
);
2071 if (!NT_STATUS_IS_OK(status
)) {
2072 DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
2076 return del_on_close
;