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 kernel share modes (flocks) 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_get_io_fd(fsp) == -1) {
79 return NT_STATUS_NOT_SUPPORTED;
82 if (is_ntfs_stream_smb_fname(fsp->fsp_name)) {
84 * We do not support durable handles
87 return NT_STATUS_NOT_SUPPORTED;
90 if (is_fake_file(fsp->fsp_name)) {
92 * We do not support durable handles
95 return NT_STATUS_NOT_SUPPORTED;
99 cookie.allow_reconnect = false;
100 cookie.id = fsp->file_id;
101 cookie.servicepath = conn->connectpath;
102 cookie.base_name = fsp->fsp_name->base_name;
103 cookie.initial_allocation_size = fsp->initial_allocation_size;
104 cookie.position_information = fh_get_position_information(fsp->fh);
105 cookie.update_write_time_triggered =
106 fsp->fsp_flags.update_write_time_triggered;
107 cookie.update_write_time_on_close =
108 fsp->fsp_flags.update_write_time_on_close;
109 cookie.write_time_forced = fsp->fsp_flags.write_time_forced;
110 cookie.close_write_time = full_timespec_to_nt_time(
111 &fsp->close_write_time);
113 cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
114 cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
115 cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
116 cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
117 cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
118 cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
119 cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
120 cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
121 cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
122 cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
123 cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
124 cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
125 cookie.stat_info.st_ex_iflags = fsp->fsp_name->st.st_ex_iflags;
126 cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
127 cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
128 cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
130 ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
131 (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
132 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
133 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
140 NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
141 const DATA_BLOB old_cookie,
143 DATA_BLOB *new_cookie)
145 struct connection_struct *conn = fsp->conn;
147 enum ndr_err_code ndr_err;
148 struct vfs_default_durable_cookie cookie;
149 DATA_BLOB new_cookie_blob = data_blob_null;
150 struct share_mode_lock *lck;
153 *new_cookie = data_blob_null;
157 ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
158 (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
159 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
160 status = ndr_map_error2ntstatus(ndr_err);
164 if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
165 return NT_STATUS_INVALID_PARAMETER;
168 if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
169 return NT_STATUS_INVALID_PARAMETER;
172 if (!file_id_equal(&fsp->file_id, &cookie.id)) {
173 return NT_STATUS_INVALID_PARAMETER;
176 if ((fsp_lease_type(fsp) & SMB2_LEASE_HANDLE) == 0) {
177 return NT_STATUS_NOT_SUPPORTED;
181 * For now let it be simple and do not keep
182 * delete on close files durable open
184 if (fsp->fsp_flags.initial_delete_on_close) {
185 return NT_STATUS_NOT_SUPPORTED;
187 if (fsp->fsp_flags.delete_on_close) {
188 return NT_STATUS_NOT_SUPPORTED;
191 if (!VALID_STAT(fsp->fsp_name->st)) {
192 return NT_STATUS_NOT_SUPPORTED;
195 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
196 return NT_STATUS_NOT_SUPPORTED;
199 /* Ensure any pending write time updates are done. */
200 if (fsp->update_write_time_event) {
201 fsp_flush_write_time_update(fsp);
205 * The above checks are done in mark_share_mode_disconnected() too
206 * but we want to avoid getting the lock if possible
208 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
210 struct smb_file_time ft;
212 init_smb_file_time(&ft);
214 if (fsp->fsp_flags.write_time_forced) {
215 NTTIME mtime = share_mode_changed_write_time(lck);
216 ft.mtime = nt_time_to_full_timespec(mtime);
217 } else if (fsp->fsp_flags.update_write_time_on_close) {
218 if (is_omit_timespec(&fsp->close_write_time)) {
219 ft.mtime = timespec_current();
221 ft.mtime = fsp->close_write_time;
225 if (!is_omit_timespec(&ft.mtime)) {
226 round_timespec(conn->ts_res, &ft.mtime);
227 file_ntimes(conn, fsp->fsp_name, &ft);
230 ok = mark_share_mode_disconnected(lck, fsp);
236 ok = brl_mark_disconnected(fsp);
242 return NT_STATUS_NOT_SUPPORTED;
246 status = vfs_stat_fsp(fsp);
247 if (!NT_STATUS_IS_OK(status)) {
252 cookie.allow_reconnect = true;
253 cookie.id = fsp->file_id;
254 cookie.servicepath = conn->connectpath;
255 cookie.base_name = fsp_str_dbg(fsp);
256 cookie.initial_allocation_size = fsp->initial_allocation_size;
257 cookie.position_information = fh_get_position_information(fsp->fh);
258 cookie.update_write_time_triggered =
259 fsp->fsp_flags.update_write_time_triggered;
260 cookie.update_write_time_on_close =
261 fsp->fsp_flags.update_write_time_on_close;
262 cookie.write_time_forced = fsp->fsp_flags.write_time_forced;
263 cookie.close_write_time = full_timespec_to_nt_time(
264 &fsp->close_write_time);
266 cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
267 cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
268 cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
269 cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
270 cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
271 cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
272 cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
273 cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
274 cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
275 cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
276 cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
277 cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
278 cookie.stat_info.st_ex_iflags = fsp->fsp_name->st.st_ex_iflags;
279 cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
280 cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
281 cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
283 ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
284 (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
285 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
286 status = ndr_map_error2ntstatus(ndr_err);
290 status = fd_close(fsp);
291 if (!NT_STATUS_IS_OK(status)) {
292 data_blob_free(&new_cookie_blob);
296 *new_cookie = new_cookie_blob;
302 * Check whether a cookie-stored struct info is the same
303 * as a given SMB_STRUCT_STAT, as coming with the fsp.
305 static bool vfs_default_durable_reconnect_check_stat(
306 struct vfs_default_durable_stat *cookie_st,
307 SMB_STRUCT_STAT *fsp_st,
312 if (cookie_st->st_ex_mode != fsp_st->st_ex_mode) {
313 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
314 "stat_ex.%s differs: "
315 "cookie:%llu != stat:%llu, "
316 "denying durable reconnect\n",
319 (unsigned long long)cookie_st->st_ex_mode,
320 (unsigned long long)fsp_st->st_ex_mode));
324 if (cookie_st->st_ex_nlink != fsp_st->st_ex_nlink) {
325 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
326 "stat_ex.%s differs: "
327 "cookie:%llu != stat:%llu, "
328 "denying durable reconnect\n",
331 (unsigned long long)cookie_st->st_ex_nlink,
332 (unsigned long long)fsp_st->st_ex_nlink));
336 if (cookie_st->st_ex_uid != fsp_st->st_ex_uid) {
337 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
338 "stat_ex.%s differs: "
339 "cookie:%llu != stat:%llu, "
340 "denying durable reconnect\n",
343 (unsigned long long)cookie_st->st_ex_uid,
344 (unsigned long long)fsp_st->st_ex_uid));
348 if (cookie_st->st_ex_gid != fsp_st->st_ex_gid) {
349 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
350 "stat_ex.%s differs: "
351 "cookie:%llu != stat:%llu, "
352 "denying durable reconnect\n",
355 (unsigned long long)cookie_st->st_ex_gid,
356 (unsigned long long)fsp_st->st_ex_gid));
360 if (cookie_st->st_ex_rdev != fsp_st->st_ex_rdev) {
361 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
362 "stat_ex.%s differs: "
363 "cookie:%llu != stat:%llu, "
364 "denying durable reconnect\n",
367 (unsigned long long)cookie_st->st_ex_rdev,
368 (unsigned long long)fsp_st->st_ex_rdev));
372 if (cookie_st->st_ex_size != fsp_st->st_ex_size) {
373 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
374 "stat_ex.%s differs: "
375 "cookie:%llu != stat:%llu, "
376 "denying durable reconnect\n",
379 (unsigned long long)cookie_st->st_ex_size,
380 (unsigned long long)fsp_st->st_ex_size));
384 ret = timespec_compare(&cookie_st->st_ex_atime,
385 &fsp_st->st_ex_atime);
387 struct timeval tc, ts;
388 tc = convert_timespec_to_timeval(cookie_st->st_ex_atime);
389 ts = convert_timespec_to_timeval(fsp_st->st_ex_atime);
391 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
392 "stat_ex.%s differs: "
393 "cookie:'%s' != stat:'%s', "
394 "denying durable reconnect\n",
397 timeval_string(talloc_tos(), &tc, true),
398 timeval_string(talloc_tos(), &ts, true)));
402 ret = timespec_compare(&cookie_st->st_ex_mtime,
403 &fsp_st->st_ex_mtime);
405 struct timeval tc, ts;
406 tc = convert_timespec_to_timeval(cookie_st->st_ex_mtime);
407 ts = convert_timespec_to_timeval(fsp_st->st_ex_mtime);
409 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
410 "stat_ex.%s differs: "
411 "cookie:'%s' != stat:'%s', "
412 "denying durable reconnect\n",
415 timeval_string(talloc_tos(), &tc, true),
416 timeval_string(talloc_tos(), &ts, true)));
420 ret = timespec_compare(&cookie_st->st_ex_ctime,
421 &fsp_st->st_ex_ctime);
423 struct timeval tc, ts;
424 tc = convert_timespec_to_timeval(cookie_st->st_ex_ctime);
425 ts = convert_timespec_to_timeval(fsp_st->st_ex_ctime);
427 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
428 "stat_ex.%s differs: "
429 "cookie:'%s' != stat:'%s', "
430 "denying durable reconnect\n",
433 timeval_string(talloc_tos(), &tc, true),
434 timeval_string(talloc_tos(), &ts, true)));
438 ret = timespec_compare(&cookie_st->st_ex_btime,
439 &fsp_st->st_ex_btime);
441 struct timeval tc, ts;
442 tc = convert_timespec_to_timeval(cookie_st->st_ex_btime);
443 ts = convert_timespec_to_timeval(fsp_st->st_ex_btime);
445 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
446 "stat_ex.%s differs: "
447 "cookie:'%s' != stat:'%s', "
448 "denying durable reconnect\n",
451 timeval_string(talloc_tos(), &tc, true),
452 timeval_string(talloc_tos(), &ts, true)));
456 if (cookie_st->st_ex_iflags != fsp_st->st_ex_iflags) {
457 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
458 "stat_ex.%s differs: "
459 "cookie:%llu != stat:%llu, "
460 "denying durable reconnect\n",
462 "st_ex_calculated_birthtime",
463 (unsigned long long)cookie_st->st_ex_iflags,
464 (unsigned long long)fsp_st->st_ex_iflags));
468 if (cookie_st->st_ex_blksize != fsp_st->st_ex_blksize) {
469 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
470 "stat_ex.%s differs: "
471 "cookie:%llu != stat:%llu, "
472 "denying durable reconnect\n",
475 (unsigned long long)cookie_st->st_ex_blksize,
476 (unsigned long long)fsp_st->st_ex_blksize));
480 if (cookie_st->st_ex_blocks != fsp_st->st_ex_blocks) {
481 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
482 "stat_ex.%s differs: "
483 "cookie:%llu != stat:%llu, "
484 "denying durable reconnect\n",
487 (unsigned long long)cookie_st->st_ex_blocks,
488 (unsigned long long)fsp_st->st_ex_blocks));
492 if (cookie_st->st_ex_flags != fsp_st->st_ex_flags) {
493 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
494 "stat_ex.%s differs: "
495 "cookie:%llu != stat:%llu, "
496 "denying durable reconnect\n",
499 (unsigned long long)cookie_st->st_ex_flags,
500 (unsigned long long)fsp_st->st_ex_flags));
507 static bool durable_reconnect_fn(
508 struct share_mode_entry *e,
512 struct share_mode_entry *dst_e = private_data;
514 if (dst_e->pid.pid != 0) {
515 DBG_INFO("Found more than one entry, invalidating previous\n");
517 return true; /* end the loop through share mode entries */
520 return false; /* Look at potential other entries */
523 NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
524 struct smb_request *smb1req,
525 struct smbXsrv_open *op,
526 const DATA_BLOB old_cookie,
528 files_struct **result,
529 DATA_BLOB *new_cookie)
531 const struct loadparm_substitution *lp_sub =
532 loadparm_s3_global_substitution();
533 struct share_mode_lock *lck;
534 struct share_mode_entry e;
535 struct files_struct *fsp = NULL;
540 struct file_id file_id;
541 struct smb_filename *smb_fname = NULL;
542 enum ndr_err_code ndr_err;
543 struct vfs_default_durable_cookie cookie;
544 DATA_BLOB new_cookie_blob = data_blob_null;
547 *new_cookie = data_blob_null;
549 if (!lp_durable_handles(SNUM(conn))) {
550 return NT_STATUS_NOT_SUPPORTED;
554 * the checks for kernel oplocks
555 * and similar things are done
556 * in the vfs_default_durable_cookie()
560 ndr_err = ndr_pull_struct_blob_all(
564 (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
565 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
566 status = ndr_map_error2ntstatus(ndr_err);
570 if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
571 return NT_STATUS_INVALID_PARAMETER;
574 if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
575 return NT_STATUS_INVALID_PARAMETER;
578 if (!cookie.allow_reconnect) {
579 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
582 if (strcmp(cookie.servicepath, conn->connectpath) != 0) {
583 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
586 /* Create an smb_filename with stream_name == NULL. */
587 smb_fname = synthetic_smb_fname(talloc_tos(),
593 if (smb_fname == NULL) {
594 return NT_STATUS_NO_MEMORY;
597 ret = SMB_VFS_LSTAT(conn, smb_fname);
599 status = map_nt_error_from_unix_common(errno);
600 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
601 smb_fname_str_dbg(smb_fname),
606 if (!S_ISREG(smb_fname->st.st_ex_mode)) {
607 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
610 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
611 if (!file_id_equal(&cookie.id, &file_id)) {
612 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
616 * 1. check entry in locking.tdb
619 lck = get_existing_share_mode_lock(mem_ctx, file_id);
621 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
622 "not obtained from db\n"));
623 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
626 e = (struct share_mode_entry) { .pid.pid = 0 };
628 ok = share_mode_forall_entries(lck, durable_reconnect_fn, &e);
630 DBG_WARNING("share_mode_forall_entries failed\n");
632 return NT_STATUS_INTERNAL_DB_ERROR;
635 if (e.pid.pid == 0) {
636 DBG_WARNING("Did not find a unique valid share mode entry\n");
638 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
641 if (!server_id_is_disconnected(&e.pid)) {
642 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
643 "reconnect for handle that was not marked "
644 "disconnected (e.g. smbd or cluster node died)\n"));
646 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
649 if (e.share_file_id != op->global->open_persistent_id) {
650 DBG_INFO("denying durable "
651 "share_file_id changed %"PRIu64" != %"PRIu64" "
652 "(e.g. another client had opened the file)\n",
654 op->global->open_persistent_id);
656 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
659 if ((e.access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
662 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
663 "share[%s] is not writeable anymore\n",
664 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
666 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
670 * 2. proceed with opening file
673 status = fsp_new(conn, conn, &fsp);
674 if (!NT_STATUS_IS_OK(status)) {
675 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
676 "new fsp: %s\n", nt_errstr(status)));
681 fh_set_private_options(fsp->fh, e.private_options);
682 fsp->file_id = file_id;
683 fsp->file_pid = smb1req->smbpid;
684 fsp->vuid = smb1req->vuid;
685 fsp->open_time = e.time;
686 fsp->access_mask = e.access_mask;
687 fsp->fsp_flags.can_read = ((fsp->access_mask & FILE_READ_DATA) != 0);
688 fsp->fsp_flags.can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
689 fsp->fnum = op->local_id;
694 * Do we need to store the modified flag in the DB?
696 fsp->fsp_flags.modified = false;
698 * no durables for directories
700 fsp->fsp_flags.is_directory = false;
702 * For normal files, can_lock == !is_directory
704 fsp->fsp_flags.can_lock = true;
706 * We do not support aio write behind for smb2
708 fsp->fsp_flags.aio_write_behind = false;
709 fsp->oplock_type = e.op_type;
711 if (fsp->oplock_type == LEASE_OPLOCK) {
712 uint32_t current_state;
713 uint16_t lease_version, epoch;
716 * Ensure the existing client guid matches the
717 * stored one in the share_mode_entry.
719 if (!GUID_equal(fsp_client_guid(fsp),
723 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
726 status = leases_db_get(
730 ¤t_state, /* current_state */
732 NULL, /* breaking_to_requested */
733 NULL, /* breaking_to_required */
734 &lease_version, /* lease_version */
736 if (!NT_STATUS_IS_OK(status)) {
742 fsp->lease = find_fsp_lease(
748 if (fsp->lease == NULL) {
751 return NT_STATUS_NO_MEMORY;
755 fsp->initial_allocation_size = cookie.initial_allocation_size;
756 fh_set_position_information(fsp->fh, cookie.position_information);
757 fsp->fsp_flags.update_write_time_triggered =
758 cookie.update_write_time_triggered;
759 fsp->fsp_flags.update_write_time_on_close =
760 cookie.update_write_time_on_close;
761 fsp->fsp_flags.write_time_forced = cookie.write_time_forced;
762 fsp->close_write_time = nt_time_to_full_timespec(
763 cookie.close_write_time);
765 status = fsp_set_smb_fname(fsp, smb_fname);
766 if (!NT_STATUS_IS_OK(status)) {
769 DEBUG(0, ("vfs_default_durable_reconnect: "
770 "fsp_set_smb_fname failed: %s\n",
778 ok = reset_share_mode_entry(
782 messaging_server_id(conn->sconn->msg_ctx),
784 fh_get_gen_id(fsp->fh));
786 DBG_DEBUG("Could not set new share_mode_entry values\n");
790 return NT_STATUS_INTERNAL_ERROR;
793 ok = brl_reconnect_disconnected(fsp);
795 status = NT_STATUS_INTERNAL_ERROR;
796 DEBUG(1, ("vfs_default_durable_reconnect: "
797 "failed to reopen brlocks: %s\n",
806 * TODO: properly calculate open flags
808 if (fsp->fsp_flags.can_write && fsp->fsp_flags.can_read) {
810 } else if (fsp->fsp_flags.can_write) {
812 } else if (fsp->fsp_flags.can_read) {
816 status = fd_openat(conn->cwd_fsp, fsp->fsp_name, fsp, flags, 0);
817 if (!NT_STATUS_IS_OK(status)) {
819 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
820 "file: %s\n", nt_errstr(status)));
827 * We now check the stat info stored in the cookie against
828 * the current stat data from the file we just opened.
829 * If any detail differs, we deny the durable reconnect,
830 * because in that case it is very likely that someone
831 * opened the file while the handle was disconnected,
832 * which has to be interpreted as an oplock break.
835 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
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 ret = SMB_VFS_CLOSE(fsp);
843 DEBUG(0, ("vfs_default_durable_reconnect: "
844 "SMB_VFS_CLOSE failed (%s) - leaking file "
845 "descriptor\n", strerror(errno)));
853 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
854 ret = SMB_VFS_CLOSE(fsp);
856 DEBUG(0, ("vfs_default_durable_reconnect: "
857 "SMB_VFS_CLOSE failed (%s) - leaking file "
858 "descriptor\n", strerror(errno)));
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 ret = SMB_VFS_CLOSE(fsp);
870 DEBUG(0, ("vfs_default_durable_reconnect: "
871 "SMB_VFS_CLOSE failed (%s) - leaking file "
872 "descriptor\n", strerror(errno)));
877 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
880 (void)dos_mode(fsp->conn, fsp->fsp_name);
882 ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info,
886 ret = SMB_VFS_CLOSE(fsp);
888 DEBUG(0, ("vfs_default_durable_reconnect: "
889 "SMB_VFS_CLOSE failed (%s) - leaking file "
890 "descriptor\n", strerror(errno)));
895 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
898 status = set_file_oplock(fsp);
899 if (!NT_STATUS_IS_OK(status)) {
900 DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
901 "after opening file: %s\n", nt_errstr(status)));
902 ret = SMB_VFS_CLOSE(fsp);
904 DEBUG(0, ("vfs_default_durable_reconnect: "
905 "SMB_VFS_CLOSE failed (%s) - leaking file "
906 "descriptor\n", strerror(errno)));
914 status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob);
915 if (!NT_STATUS_IS_OK(status)) {
917 DEBUG(1, ("vfs_default_durable_reconnect: "
918 "vfs_default_durable_cookie - %s\n",
925 smb1req->chain_fsp = fsp;
926 smb1req->smb2req->compat_chain_fsp = fsp;
928 DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
934 *new_cookie = new_cookie_blob;