2 Unix SMB/CIFS implementation.
3 Durable Handle default VFS implementation
5 Copyright (C) Stefan Metzmacher 2012
6 Copyright (C) Michael Adam 2012
7 Copyright (C) Volker Lendecke 2012
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/filesys.h"
25 #include "lib/util/server_id.h"
26 #include "locking/share_mode_lock.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
29 #include "libcli/security/security.h"
31 #include "librpc/gen_ndr/ndr_open_files.h"
33 #include "fake_file.h"
34 #include "locking/leases_db.h"
36 NTSTATUS
vfs_default_durable_cookie(struct files_struct
*fsp
,
38 DATA_BLOB
*cookie_blob
)
40 struct connection_struct
*conn
= fsp
->conn
;
41 enum ndr_err_code ndr_err
;
42 struct vfs_default_durable_cookie cookie
;
44 if (!lp_durable_handles(SNUM(conn
))) {
45 return NT_STATUS_NOT_SUPPORTED
;
48 if (lp_kernel_share_modes(SNUM(conn
))) {
50 * We do not support durable handles
51 * if file system sharemodes are used
53 return NT_STATUS_NOT_SUPPORTED
;
56 if (lp_kernel_oplocks(SNUM(conn
))) {
58 * We do not support durable handles
59 * if kernel oplocks are used
61 return NT_STATUS_NOT_SUPPORTED
;
64 if ((fsp
->current_lock_count
> 0) &&
65 lp_posix_locking(fsp
->conn
->params
))
68 * We do not support durable handles
69 * if the handle has posix locks.
71 return NT_STATUS_NOT_SUPPORTED
;
74 if (fsp
->fsp_flags
.is_directory
) {
75 return NT_STATUS_NOT_SUPPORTED
;
78 if (fsp_is_alternate_stream(fsp
)) {
80 * We do not support durable handles
83 return NT_STATUS_NOT_SUPPORTED
;
86 if (is_fake_file(fsp
->fsp_name
)) {
88 * We do not support durable handles
91 return NT_STATUS_NOT_SUPPORTED
;
95 cookie
.allow_reconnect
= false;
96 cookie
.id
= fsp
->file_id
;
97 cookie
.servicepath
= conn
->connectpath
;
98 cookie
.base_name
= fsp
->fsp_name
->base_name
;
99 cookie
.initial_allocation_size
= fsp
->initial_allocation_size
;
100 cookie
.position_information
= fh_get_position_information(fsp
->fh
);
101 cookie
.update_write_time_triggered
=
102 fsp
->fsp_flags
.update_write_time_triggered
;
103 cookie
.update_write_time_on_close
=
104 fsp
->fsp_flags
.update_write_time_on_close
;
105 cookie
.write_time_forced
= fsp
->fsp_flags
.write_time_forced
;
106 cookie
.close_write_time
= full_timespec_to_nt_time(
107 &fsp
->close_write_time
);
109 cookie
.stat_info
.st_ex_dev
= fsp
->fsp_name
->st
.st_ex_dev
;
110 cookie
.stat_info
.st_ex_ino
= fsp
->fsp_name
->st
.st_ex_ino
;
111 cookie
.stat_info
.st_ex_mode
= fsp
->fsp_name
->st
.st_ex_mode
;
112 cookie
.stat_info
.st_ex_nlink
= fsp
->fsp_name
->st
.st_ex_nlink
;
113 cookie
.stat_info
.st_ex_uid
= fsp
->fsp_name
->st
.st_ex_uid
;
114 cookie
.stat_info
.st_ex_gid
= fsp
->fsp_name
->st
.st_ex_gid
;
115 cookie
.stat_info
.st_ex_rdev
= fsp
->fsp_name
->st
.st_ex_rdev
;
116 cookie
.stat_info
.st_ex_size
= fsp
->fsp_name
->st
.st_ex_size
;
117 cookie
.stat_info
.st_ex_atime
= fsp
->fsp_name
->st
.st_ex_atime
;
118 cookie
.stat_info
.st_ex_mtime
= fsp
->fsp_name
->st
.st_ex_mtime
;
119 cookie
.stat_info
.st_ex_ctime
= fsp
->fsp_name
->st
.st_ex_ctime
;
120 cookie
.stat_info
.st_ex_btime
= fsp
->fsp_name
->st
.st_ex_btime
;
121 cookie
.stat_info
.st_ex_iflags
= fsp
->fsp_name
->st
.st_ex_iflags
;
122 cookie
.stat_info
.st_ex_blksize
= fsp
->fsp_name
->st
.st_ex_blksize
;
123 cookie
.stat_info
.st_ex_blocks
= fsp
->fsp_name
->st
.st_ex_blocks
;
124 cookie
.stat_info
.st_ex_flags
= fsp
->fsp_name
->st
.st_ex_flags
;
126 ndr_err
= ndr_push_struct_blob(cookie_blob
, mem_ctx
, &cookie
,
127 (ndr_push_flags_fn_t
)ndr_push_vfs_default_durable_cookie
);
128 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
129 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
136 NTSTATUS
vfs_default_durable_disconnect(struct files_struct
*fsp
,
137 const DATA_BLOB old_cookie
,
139 DATA_BLOB
*new_cookie
)
141 struct connection_struct
*conn
= fsp
->conn
;
143 enum ndr_err_code ndr_err
;
144 struct vfs_default_durable_cookie cookie
;
145 DATA_BLOB new_cookie_blob
= data_blob_null
;
146 struct share_mode_lock
*lck
;
149 *new_cookie
= data_blob_null
;
153 ndr_err
= ndr_pull_struct_blob(&old_cookie
, talloc_tos(), &cookie
,
154 (ndr_pull_flags_fn_t
)ndr_pull_vfs_default_durable_cookie
);
155 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
156 status
= ndr_map_error2ntstatus(ndr_err
);
160 if (strcmp(cookie
.magic
, VFS_DEFAULT_DURABLE_COOKIE_MAGIC
) != 0) {
161 return NT_STATUS_INVALID_PARAMETER
;
164 if (cookie
.version
!= VFS_DEFAULT_DURABLE_COOKIE_VERSION
) {
165 return NT_STATUS_INVALID_PARAMETER
;
168 if (!file_id_equal(&fsp
->file_id
, &cookie
.id
)) {
169 return NT_STATUS_INVALID_PARAMETER
;
172 if ((fsp_lease_type(fsp
) & SMB2_LEASE_HANDLE
) == 0) {
173 return NT_STATUS_NOT_SUPPORTED
;
177 * For now let it be simple and do not keep
178 * delete on close files durable open
180 if (fsp
->fsp_flags
.initial_delete_on_close
) {
181 return NT_STATUS_NOT_SUPPORTED
;
183 if (fsp
->fsp_flags
.delete_on_close
) {
184 return NT_STATUS_NOT_SUPPORTED
;
187 if (!VALID_STAT(fsp
->fsp_name
->st
)) {
188 return NT_STATUS_NOT_SUPPORTED
;
191 if (!S_ISREG(fsp
->fsp_name
->st
.st_ex_mode
)) {
192 return NT_STATUS_NOT_SUPPORTED
;
195 /* Ensure any pending write time updates are done. */
196 if (fsp
->update_write_time_event
) {
197 fsp_flush_write_time_update(fsp
);
201 * The above checks are done in mark_share_mode_disconnected() too
202 * but we want to avoid getting the lock if possible
204 lck
= get_existing_share_mode_lock(talloc_tos(), fsp
->file_id
);
206 struct smb_file_time ft
;
208 init_smb_file_time(&ft
);
210 if (fsp
->fsp_flags
.write_time_forced
) {
211 NTTIME mtime
= share_mode_changed_write_time(lck
);
212 ft
.mtime
= nt_time_to_full_timespec(mtime
);
213 } else if (fsp
->fsp_flags
.update_write_time_on_close
) {
214 if (is_omit_timespec(&fsp
->close_write_time
)) {
215 ft
.mtime
= timespec_current();
217 ft
.mtime
= fsp
->close_write_time
;
221 if (!is_omit_timespec(&ft
.mtime
)) {
222 round_timespec(conn
->ts_res
, &ft
.mtime
);
223 file_ntimes(conn
, fsp
, &ft
);
226 ok
= mark_share_mode_disconnected(lck
, fsp
);
232 ok
= brl_mark_disconnected(fsp
);
238 return NT_STATUS_NOT_SUPPORTED
;
242 status
= vfs_stat_fsp(fsp
);
243 if (!NT_STATUS_IS_OK(status
)) {
248 cookie
.allow_reconnect
= true;
249 cookie
.id
= fsp
->file_id
;
250 cookie
.servicepath
= conn
->connectpath
;
251 cookie
.base_name
= fsp_str_dbg(fsp
);
252 cookie
.initial_allocation_size
= fsp
->initial_allocation_size
;
253 cookie
.position_information
= fh_get_position_information(fsp
->fh
);
254 cookie
.update_write_time_triggered
=
255 fsp
->fsp_flags
.update_write_time_triggered
;
256 cookie
.update_write_time_on_close
=
257 fsp
->fsp_flags
.update_write_time_on_close
;
258 cookie
.write_time_forced
= fsp
->fsp_flags
.write_time_forced
;
259 cookie
.close_write_time
= full_timespec_to_nt_time(
260 &fsp
->close_write_time
);
262 cookie
.stat_info
.st_ex_dev
= fsp
->fsp_name
->st
.st_ex_dev
;
263 cookie
.stat_info
.st_ex_ino
= fsp
->fsp_name
->st
.st_ex_ino
;
264 cookie
.stat_info
.st_ex_mode
= fsp
->fsp_name
->st
.st_ex_mode
;
265 cookie
.stat_info
.st_ex_nlink
= fsp
->fsp_name
->st
.st_ex_nlink
;
266 cookie
.stat_info
.st_ex_uid
= fsp
->fsp_name
->st
.st_ex_uid
;
267 cookie
.stat_info
.st_ex_gid
= fsp
->fsp_name
->st
.st_ex_gid
;
268 cookie
.stat_info
.st_ex_rdev
= fsp
->fsp_name
->st
.st_ex_rdev
;
269 cookie
.stat_info
.st_ex_size
= fsp
->fsp_name
->st
.st_ex_size
;
270 cookie
.stat_info
.st_ex_atime
= fsp
->fsp_name
->st
.st_ex_atime
;
271 cookie
.stat_info
.st_ex_mtime
= fsp
->fsp_name
->st
.st_ex_mtime
;
272 cookie
.stat_info
.st_ex_ctime
= fsp
->fsp_name
->st
.st_ex_ctime
;
273 cookie
.stat_info
.st_ex_btime
= fsp
->fsp_name
->st
.st_ex_btime
;
274 cookie
.stat_info
.st_ex_iflags
= fsp
->fsp_name
->st
.st_ex_iflags
;
275 cookie
.stat_info
.st_ex_blksize
= fsp
->fsp_name
->st
.st_ex_blksize
;
276 cookie
.stat_info
.st_ex_blocks
= fsp
->fsp_name
->st
.st_ex_blocks
;
277 cookie
.stat_info
.st_ex_flags
= fsp
->fsp_name
->st
.st_ex_flags
;
279 ndr_err
= ndr_push_struct_blob(&new_cookie_blob
, mem_ctx
, &cookie
,
280 (ndr_push_flags_fn_t
)ndr_push_vfs_default_durable_cookie
);
281 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
282 status
= ndr_map_error2ntstatus(ndr_err
);
286 status
= fd_close(fsp
);
287 if (!NT_STATUS_IS_OK(status
)) {
288 data_blob_free(&new_cookie_blob
);
292 *new_cookie
= new_cookie_blob
;
298 * Check whether a cookie-stored struct info is the same
299 * as a given SMB_STRUCT_STAT, as coming with the fsp.
301 static bool vfs_default_durable_reconnect_check_stat(
302 struct vfs_default_durable_stat
*cookie_st
,
303 SMB_STRUCT_STAT
*fsp_st
,
308 if (cookie_st
->st_ex_mode
!= fsp_st
->st_ex_mode
) {
309 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
310 "stat_ex.%s differs: "
311 "cookie:%llu != stat:%llu, "
312 "denying durable reconnect\n",
315 (unsigned long long)cookie_st
->st_ex_mode
,
316 (unsigned long long)fsp_st
->st_ex_mode
));
320 if (cookie_st
->st_ex_nlink
!= fsp_st
->st_ex_nlink
) {
321 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
322 "stat_ex.%s differs: "
323 "cookie:%llu != stat:%llu, "
324 "denying durable reconnect\n",
327 (unsigned long long)cookie_st
->st_ex_nlink
,
328 (unsigned long long)fsp_st
->st_ex_nlink
));
332 if (cookie_st
->st_ex_uid
!= fsp_st
->st_ex_uid
) {
333 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
334 "stat_ex.%s differs: "
335 "cookie:%llu != stat:%llu, "
336 "denying durable reconnect\n",
339 (unsigned long long)cookie_st
->st_ex_uid
,
340 (unsigned long long)fsp_st
->st_ex_uid
));
344 if (cookie_st
->st_ex_gid
!= fsp_st
->st_ex_gid
) {
345 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
346 "stat_ex.%s differs: "
347 "cookie:%llu != stat:%llu, "
348 "denying durable reconnect\n",
351 (unsigned long long)cookie_st
->st_ex_gid
,
352 (unsigned long long)fsp_st
->st_ex_gid
));
356 if (cookie_st
->st_ex_rdev
!= fsp_st
->st_ex_rdev
) {
357 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
358 "stat_ex.%s differs: "
359 "cookie:%llu != stat:%llu, "
360 "denying durable reconnect\n",
363 (unsigned long long)cookie_st
->st_ex_rdev
,
364 (unsigned long long)fsp_st
->st_ex_rdev
));
368 if (cookie_st
->st_ex_size
!= fsp_st
->st_ex_size
) {
369 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
370 "stat_ex.%s differs: "
371 "cookie:%llu != stat:%llu, "
372 "denying durable reconnect\n",
375 (unsigned long long)cookie_st
->st_ex_size
,
376 (unsigned long long)fsp_st
->st_ex_size
));
380 ret
= timespec_compare(&cookie_st
->st_ex_atime
,
381 &fsp_st
->st_ex_atime
);
383 struct timeval tc
, ts
;
384 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_atime
);
385 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_atime
);
387 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
388 "stat_ex.%s differs: "
389 "cookie:'%s' != stat:'%s', "
390 "denying durable reconnect\n",
393 timeval_string(talloc_tos(), &tc
, true),
394 timeval_string(talloc_tos(), &ts
, true)));
398 ret
= timespec_compare(&cookie_st
->st_ex_mtime
,
399 &fsp_st
->st_ex_mtime
);
401 struct timeval tc
, ts
;
402 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_mtime
);
403 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_mtime
);
405 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
406 "stat_ex.%s differs: "
407 "cookie:'%s' != stat:'%s', "
408 "denying durable reconnect\n",
411 timeval_string(talloc_tos(), &tc
, true),
412 timeval_string(talloc_tos(), &ts
, true)));
416 ret
= timespec_compare(&cookie_st
->st_ex_ctime
,
417 &fsp_st
->st_ex_ctime
);
419 struct timeval tc
, ts
;
420 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_ctime
);
421 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_ctime
);
423 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
424 "stat_ex.%s differs: "
425 "cookie:'%s' != stat:'%s', "
426 "denying durable reconnect\n",
429 timeval_string(talloc_tos(), &tc
, true),
430 timeval_string(talloc_tos(), &ts
, true)));
434 ret
= timespec_compare(&cookie_st
->st_ex_btime
,
435 &fsp_st
->st_ex_btime
);
437 struct timeval tc
, ts
;
438 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_btime
);
439 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_btime
);
441 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
442 "stat_ex.%s differs: "
443 "cookie:'%s' != stat:'%s', "
444 "denying durable reconnect\n",
447 timeval_string(talloc_tos(), &tc
, true),
448 timeval_string(talloc_tos(), &ts
, true)));
452 if (cookie_st
->st_ex_iflags
!= fsp_st
->st_ex_iflags
) {
453 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
454 "stat_ex.%s differs: "
455 "cookie:%llu != stat:%llu, "
456 "denying durable reconnect\n",
458 "st_ex_calculated_birthtime",
459 (unsigned long long)cookie_st
->st_ex_iflags
,
460 (unsigned long long)fsp_st
->st_ex_iflags
));
464 if (cookie_st
->st_ex_blksize
!= fsp_st
->st_ex_blksize
) {
465 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
466 "stat_ex.%s differs: "
467 "cookie:%llu != stat:%llu, "
468 "denying durable reconnect\n",
471 (unsigned long long)cookie_st
->st_ex_blksize
,
472 (unsigned long long)fsp_st
->st_ex_blksize
));
476 if (cookie_st
->st_ex_blocks
!= fsp_st
->st_ex_blocks
) {
477 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
478 "stat_ex.%s differs: "
479 "cookie:%llu != stat:%llu, "
480 "denying durable reconnect\n",
483 (unsigned long long)cookie_st
->st_ex_blocks
,
484 (unsigned long long)fsp_st
->st_ex_blocks
));
488 if (cookie_st
->st_ex_flags
!= fsp_st
->st_ex_flags
) {
489 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
490 "stat_ex.%s differs: "
491 "cookie:%llu != stat:%llu, "
492 "denying durable reconnect\n",
495 (unsigned long long)cookie_st
->st_ex_flags
,
496 (unsigned long long)fsp_st
->st_ex_flags
));
503 static bool durable_reconnect_fn(
504 struct share_mode_entry
*e
,
508 struct share_mode_entry
*dst_e
= private_data
;
510 if (dst_e
->pid
.pid
!= 0) {
511 DBG_INFO("Found more than one entry, invalidating previous\n");
513 return true; /* end the loop through share mode entries */
516 return false; /* Look at potential other entries */
519 NTSTATUS
vfs_default_durable_reconnect(struct connection_struct
*conn
,
520 struct smb_request
*smb1req
,
521 struct smbXsrv_open
*op
,
522 const DATA_BLOB old_cookie
,
524 files_struct
**result
,
525 DATA_BLOB
*new_cookie
)
527 const struct loadparm_substitution
*lp_sub
=
528 loadparm_s3_global_substitution();
529 struct share_mode_lock
*lck
;
530 struct share_mode_entry e
;
531 struct files_struct
*fsp
= NULL
;
535 struct vfs_open_how how
= { .flags
= 0, };
536 struct file_id file_id
;
537 struct smb_filename
*smb_fname
= NULL
;
538 enum ndr_err_code ndr_err
;
539 struct vfs_default_durable_cookie cookie
;
540 DATA_BLOB new_cookie_blob
= data_blob_null
;
543 *new_cookie
= data_blob_null
;
545 if (!lp_durable_handles(SNUM(conn
))) {
546 return NT_STATUS_NOT_SUPPORTED
;
550 * the checks for kernel oplocks
551 * and similar things are done
552 * in the vfs_default_durable_cookie()
556 ndr_err
= ndr_pull_struct_blob_all(
560 (ndr_pull_flags_fn_t
)ndr_pull_vfs_default_durable_cookie
);
561 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
562 status
= ndr_map_error2ntstatus(ndr_err
);
566 if (strcmp(cookie
.magic
, VFS_DEFAULT_DURABLE_COOKIE_MAGIC
) != 0) {
567 return NT_STATUS_INVALID_PARAMETER
;
570 if (cookie
.version
!= VFS_DEFAULT_DURABLE_COOKIE_VERSION
) {
571 return NT_STATUS_INVALID_PARAMETER
;
574 if (!cookie
.allow_reconnect
) {
575 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
578 if (strcmp(cookie
.servicepath
, conn
->connectpath
) != 0) {
579 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
582 /* Create an smb_filename with stream_name == NULL. */
583 smb_fname
= synthetic_smb_fname(talloc_tos(),
589 if (smb_fname
== NULL
) {
590 return NT_STATUS_NO_MEMORY
;
593 ret
= SMB_VFS_LSTAT(conn
, smb_fname
);
595 status
= map_nt_error_from_unix_common(errno
);
596 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
597 smb_fname_str_dbg(smb_fname
),
602 if (!S_ISREG(smb_fname
->st
.st_ex_mode
)) {
603 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
606 file_id
= vfs_file_id_from_sbuf(conn
, &smb_fname
->st
);
607 if (!file_id_equal(&cookie
.id
, &file_id
)) {
608 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
612 * 1. check entry in locking.tdb
615 lck
= get_existing_share_mode_lock(mem_ctx
, file_id
);
617 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
618 "not obtained from db\n"));
619 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
622 e
= (struct share_mode_entry
) { .pid
.pid
= 0 };
624 ok
= share_mode_forall_entries(lck
, durable_reconnect_fn
, &e
);
626 DBG_WARNING("share_mode_forall_entries failed\n");
628 return NT_STATUS_INTERNAL_DB_ERROR
;
631 if (e
.pid
.pid
== 0) {
632 DBG_WARNING("Did not find a unique valid share mode entry\n");
634 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
637 if (!server_id_is_disconnected(&e
.pid
)) {
638 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
639 "reconnect for handle that was not marked "
640 "disconnected (e.g. smbd or cluster node died)\n"));
642 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
645 if (e
.share_file_id
!= op
->global
->open_persistent_id
) {
646 DBG_INFO("denying durable "
647 "share_file_id changed %"PRIu64
" != %"PRIu64
" "
648 "(e.g. another client had opened the file)\n",
650 op
->global
->open_persistent_id
);
652 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
655 if ((e
.access_mask
& (FILE_WRITE_DATA
|FILE_APPEND_DATA
)) &&
658 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
659 "share[%s] is not writeable anymore\n",
660 lp_servicename(talloc_tos(), lp_sub
, SNUM(conn
))));
662 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
666 * 2. proceed with opening file
669 status
= fsp_new(conn
, conn
, &fsp
);
670 if (!NT_STATUS_IS_OK(status
)) {
671 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
672 "new fsp: %s\n", nt_errstr(status
)));
677 fh_set_private_options(fsp
->fh
, e
.private_options
);
678 fsp
->file_id
= file_id
;
679 fsp
->file_pid
= smb1req
->smbpid
;
680 fsp
->vuid
= smb1req
->vuid
;
681 fsp
->open_time
= e
.time
;
682 fsp
->access_mask
= e
.access_mask
;
683 fsp
->fsp_flags
.can_read
= ((fsp
->access_mask
& FILE_READ_DATA
) != 0);
684 fsp
->fsp_flags
.can_write
= ((fsp
->access_mask
& (FILE_WRITE_DATA
|FILE_APPEND_DATA
)) != 0);
685 fsp
->fnum
= op
->local_id
;
690 * Do we need to store the modified flag in the DB?
692 fsp
->fsp_flags
.modified
= false;
694 * no durables for directories
696 fsp
->fsp_flags
.is_directory
= false;
698 * For normal files, can_lock == !is_directory
700 fsp
->fsp_flags
.can_lock
= true;
702 * We do not support aio write behind for smb2
704 fsp
->fsp_flags
.aio_write_behind
= false;
705 fsp
->oplock_type
= e
.op_type
;
707 if (fsp
->oplock_type
== LEASE_OPLOCK
) {
708 uint32_t current_state
;
709 uint16_t lease_version
, epoch
;
712 * Ensure the existing client guid matches the
713 * stored one in the share_mode_entry.
715 if (!GUID_equal(fsp_client_guid(fsp
),
718 file_free(smb1req
, fsp
);
719 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
722 status
= leases_db_get(
726 ¤t_state
, /* current_state */
728 NULL
, /* breaking_to_requested */
729 NULL
, /* breaking_to_required */
730 &lease_version
, /* lease_version */
732 if (!NT_STATUS_IS_OK(status
)) {
734 file_free(smb1req
, fsp
);
738 fsp
->lease
= find_fsp_lease(
744 if (fsp
->lease
== NULL
) {
746 file_free(smb1req
, fsp
);
747 return NT_STATUS_NO_MEMORY
;
751 fsp
->initial_allocation_size
= cookie
.initial_allocation_size
;
752 fh_set_position_information(fsp
->fh
, cookie
.position_information
);
753 fsp
->fsp_flags
.update_write_time_triggered
=
754 cookie
.update_write_time_triggered
;
755 fsp
->fsp_flags
.update_write_time_on_close
=
756 cookie
.update_write_time_on_close
;
757 fsp
->fsp_flags
.write_time_forced
= cookie
.write_time_forced
;
758 fsp
->close_write_time
= nt_time_to_full_timespec(
759 cookie
.close_write_time
);
761 status
= fsp_set_smb_fname(fsp
, smb_fname
);
762 if (!NT_STATUS_IS_OK(status
)) {
764 file_free(smb1req
, fsp
);
765 DEBUG(0, ("vfs_default_durable_reconnect: "
766 "fsp_set_smb_fname failed: %s\n",
774 ok
= reset_share_mode_entry(
778 messaging_server_id(conn
->sconn
->msg_ctx
),
780 fh_get_gen_id(fsp
->fh
));
782 DBG_DEBUG("Could not set new share_mode_entry values\n");
786 file_free(smb1req
, fsp
);
787 return NT_STATUS_INTERNAL_ERROR
;
790 ok
= brl_reconnect_disconnected(fsp
);
792 status
= NT_STATUS_INTERNAL_ERROR
;
793 DEBUG(1, ("vfs_default_durable_reconnect: "
794 "failed to reopen brlocks: %s\n",
799 file_free(smb1req
, fsp
);
804 * TODO: properly calculate open flags
806 if (fsp
->fsp_flags
.can_write
&& fsp
->fsp_flags
.can_read
) {
808 } else if (fsp
->fsp_flags
.can_write
) {
809 how
.flags
= O_WRONLY
;
810 } else if (fsp
->fsp_flags
.can_read
) {
811 how
.flags
= O_RDONLY
;
814 status
= fd_openat(conn
->cwd_fsp
, fsp
->fsp_name
, fsp
, &how
);
815 if (!NT_STATUS_IS_OK(status
)) {
817 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
818 "file: %s\n", nt_errstr(status
)));
821 file_free(smb1req
, fsp
);
826 * We now check the stat info stored in the cookie against
827 * the current stat data from the file we just opened.
828 * If any detail differs, we deny the durable reconnect,
829 * because in that case it is very likely that someone
830 * opened the file while the handle was disconnected,
831 * which has to be interpreted as an oplock break.
834 ret
= SMB_VFS_FSTAT(fsp
, &fsp
->fsp_name
->st
);
836 NTSTATUS close_status
;
837 status
= map_nt_error_from_unix_common(errno
);
838 DEBUG(1, ("Unable to fstat stream: %s => %s\n",
839 smb_fname_str_dbg(smb_fname
),
841 close_status
= fd_close(fsp
);
842 if (!NT_STATUS_IS_OK(close_status
)) {
843 DBG_ERR("fd_close failed (%s) - leaking file "
844 "descriptor\n", nt_errstr(close_status
));
849 file_free(smb1req
, fsp
);
853 if (!S_ISREG(fsp
->fsp_name
->st
.st_ex_mode
)) {
854 NTSTATUS close_status
= fd_close(fsp
);
855 if (!NT_STATUS_IS_OK(close_status
)) {
856 DBG_ERR("fd_close failed (%s) - leaking file "
857 "descriptor\n", nt_errstr(close_status
));
862 file_free(smb1req
, fsp
);
863 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
866 file_id
= vfs_file_id_from_sbuf(conn
, &fsp
->fsp_name
->st
);
867 if (!file_id_equal(&cookie
.id
, &file_id
)) {
868 NTSTATUS close_status
= fd_close(fsp
);
869 if (!NT_STATUS_IS_OK(close_status
)) {
870 DBG_ERR("fd_close failed (%s) - leaking file "
871 "descriptor\n", nt_errstr(close_status
));
876 file_free(smb1req
, fsp
);
877 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
880 (void)fdos_mode(fsp
);
882 ok
= vfs_default_durable_reconnect_check_stat(&cookie
.stat_info
,
886 NTSTATUS close_status
= fd_close(fsp
);
887 if (!NT_STATUS_IS_OK(close_status
)) {
888 DBG_ERR("fd_close failed (%s) - leaking file "
889 "descriptor\n", nt_errstr(close_status
));
894 file_free(smb1req
, fsp
);
895 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
898 status
= set_file_oplock(fsp
);
899 if (!NT_STATUS_IS_OK(status
)) {
900 NTSTATUS close_status
= fd_close(fsp
);
901 if (!NT_STATUS_IS_OK(close_status
)) {
902 DBG_ERR("fd_close failed (%s) - leaking file "
903 "descriptor\n", nt_errstr(close_status
));
908 file_free(smb1req
, fsp
);
912 status
= vfs_default_durable_cookie(fsp
, mem_ctx
, &new_cookie_blob
);
913 if (!NT_STATUS_IS_OK(status
)) {
915 DEBUG(1, ("vfs_default_durable_reconnect: "
916 "vfs_default_durable_cookie - %s\n",
920 file_free(smb1req
, fsp
);
924 smb1req
->chain_fsp
= fsp
;
925 smb1req
->smb2req
->compat_chain_fsp
= fsp
;
927 DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
932 fsp
->fsp_flags
.is_fsa
= true;
935 *new_cookie
= new_cookie_blob
;