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