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 "smbd/smbd.h"
27 #include "smbd/globals.h"
28 #include "libcli/security/security.h"
30 #include "librpc/gen_ndr/ndr_open_files.h"
32 #include "fake_file.h"
33 #include "locking/leases_db.h"
35 NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
37 DATA_BLOB *cookie_blob)
39 struct connection_struct *conn = fsp->conn;
40 enum ndr_err_code ndr_err;
41 struct vfs_default_durable_cookie cookie;
43 if (!lp_durable_handles(SNUM(conn))) {
44 return NT_STATUS_NOT_SUPPORTED;
47 if (lp_kernel_share_modes(SNUM(conn))) {
49 * We do not support durable handles
50 * if kernel share modes (flocks) are used
52 return NT_STATUS_NOT_SUPPORTED;
55 if (lp_kernel_oplocks(SNUM(conn))) {
57 * We do not support durable handles
58 * if kernel oplocks are used
60 return NT_STATUS_NOT_SUPPORTED;
63 if ((fsp->current_lock_count > 0) &&
64 lp_posix_locking(fsp->conn->params))
67 * We do not support durable handles
68 * if the handle has posix locks.
70 return NT_STATUS_NOT_SUPPORTED;
73 if (fsp->is_directory) {
74 return NT_STATUS_NOT_SUPPORTED;
77 if (fsp->fh->fd == -1) {
78 return NT_STATUS_NOT_SUPPORTED;
81 if (is_ntfs_stream_smb_fname(fsp->fsp_name)) {
83 * We do not support durable handles
86 return NT_STATUS_NOT_SUPPORTED;
89 if (is_fake_file(fsp->fsp_name)) {
91 * We do not support durable handles
94 return NT_STATUS_NOT_SUPPORTED;
98 cookie.allow_reconnect = false;
99 cookie.id = fsp->file_id;
100 cookie.servicepath = conn->connectpath;
101 cookie.base_name = fsp->fsp_name->base_name;
102 cookie.initial_allocation_size = fsp->initial_allocation_size;
103 cookie.position_information = fsp->fh->position_information;
104 cookie.update_write_time_triggered =
105 fsp->fsp_flags.update_write_time_triggered;
106 cookie.update_write_time_on_close =
107 fsp->fsp_flags.update_write_time_on_close;
108 cookie.write_time_forced = fsp->fsp_flags.write_time_forced;
109 cookie.close_write_time = full_timespec_to_nt_time(
110 &fsp->close_write_time);
112 cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
113 cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
114 cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
115 cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
116 cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
117 cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
118 cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
119 cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
120 cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
121 cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
122 cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
123 cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
124 cookie.stat_info.st_ex_iflags = fsp->fsp_name->st.st_ex_iflags;
125 cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
126 cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
127 cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
129 ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
130 (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
131 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
132 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
139 NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
140 const DATA_BLOB old_cookie,
142 DATA_BLOB *new_cookie)
144 struct connection_struct *conn = fsp->conn;
146 enum ndr_err_code ndr_err;
147 struct vfs_default_durable_cookie cookie;
148 DATA_BLOB new_cookie_blob = data_blob_null;
149 struct share_mode_lock *lck;
152 *new_cookie = data_blob_null;
156 ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
157 (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
158 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
159 status = ndr_map_error2ntstatus(ndr_err);
163 if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
164 return NT_STATUS_INVALID_PARAMETER;
167 if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
168 return NT_STATUS_INVALID_PARAMETER;
171 if (!file_id_equal(&fsp->file_id, &cookie.id)) {
172 return NT_STATUS_INVALID_PARAMETER;
175 if ((fsp_lease_type(fsp) & SMB2_LEASE_HANDLE) == 0) {
176 return NT_STATUS_NOT_SUPPORTED;
180 * For now let it be simple and do not keep
181 * delete on close files durable open
183 if (fsp->initial_delete_on_close) {
184 return NT_STATUS_NOT_SUPPORTED;
186 if (fsp->delete_on_close) {
187 return NT_STATUS_NOT_SUPPORTED;
190 if (!VALID_STAT(fsp->fsp_name->st)) {
191 return NT_STATUS_NOT_SUPPORTED;
194 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
195 return NT_STATUS_NOT_SUPPORTED;
198 /* Ensure any pending write time updates are done. */
199 if (fsp->update_write_time_event) {
200 fsp_flush_write_time_update(fsp);
204 * The above checks are done in mark_share_mode_disconnected() too
205 * but we want to avoid getting the lock if possible
207 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
209 struct smb_file_time ft;
211 init_smb_file_time(&ft);
213 if (fsp->fsp_flags.write_time_forced) {
214 ft.mtime = nt_time_to_full_timespec(
215 lck->data->changed_write_time);
216 } else if (fsp->fsp_flags.update_write_time_on_close) {
217 if (is_omit_timespec(&fsp->close_write_time)) {
218 ft.mtime = timespec_current();
220 ft.mtime = fsp->close_write_time;
224 if (!is_omit_timespec(&ft.mtime)) {
225 round_timespec(conn->ts_res, &ft.mtime);
226 file_ntimes(conn, fsp->fsp_name, &ft);
229 ok = mark_share_mode_disconnected(lck, fsp);
235 ok = brl_mark_disconnected(fsp);
241 return NT_STATUS_NOT_SUPPORTED;
245 status = vfs_stat_fsp(fsp);
246 if (!NT_STATUS_IS_OK(status)) {
251 cookie.allow_reconnect = true;
252 cookie.id = fsp->file_id;
253 cookie.servicepath = conn->connectpath;
254 cookie.base_name = fsp->fsp_name->base_name;
255 cookie.initial_allocation_size = fsp->initial_allocation_size;
256 cookie.position_information = fsp->fh->position_information;
257 cookie.update_write_time_triggered =
258 fsp->fsp_flags.update_write_time_triggered;
259 cookie.update_write_time_on_close =
260 fsp->fsp_flags.update_write_time_on_close;
261 cookie.write_time_forced = fsp->fsp_flags.write_time_forced;
262 cookie.close_write_time = full_timespec_to_nt_time(
263 &fsp->close_write_time);
265 cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
266 cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
267 cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
268 cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
269 cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
270 cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
271 cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
272 cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
273 cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
274 cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
275 cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
276 cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
277 cookie.stat_info.st_ex_iflags = fsp->fsp_name->st.st_ex_iflags;
278 cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
279 cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
280 cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
282 ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
283 (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
284 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
285 status = ndr_map_error2ntstatus(ndr_err);
289 status = fd_close(fsp);
290 if (!NT_STATUS_IS_OK(status)) {
291 data_blob_free(&new_cookie_blob);
295 *new_cookie = new_cookie_blob;
301 * Check whether a cookie-stored struct info is the same
302 * as a given SMB_STRUCT_STAT, as coming with the fsp.
304 static bool vfs_default_durable_reconnect_check_stat(
305 struct vfs_default_durable_stat *cookie_st,
306 SMB_STRUCT_STAT *fsp_st,
311 if (cookie_st->st_ex_mode != fsp_st->st_ex_mode) {
312 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
313 "stat_ex.%s differs: "
314 "cookie:%llu != stat:%llu, "
315 "denying durable reconnect\n",
318 (unsigned long long)cookie_st->st_ex_mode,
319 (unsigned long long)fsp_st->st_ex_mode));
323 if (cookie_st->st_ex_nlink != fsp_st->st_ex_nlink) {
324 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
325 "stat_ex.%s differs: "
326 "cookie:%llu != stat:%llu, "
327 "denying durable reconnect\n",
330 (unsigned long long)cookie_st->st_ex_nlink,
331 (unsigned long long)fsp_st->st_ex_nlink));
335 if (cookie_st->st_ex_uid != fsp_st->st_ex_uid) {
336 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
337 "stat_ex.%s differs: "
338 "cookie:%llu != stat:%llu, "
339 "denying durable reconnect\n",
342 (unsigned long long)cookie_st->st_ex_uid,
343 (unsigned long long)fsp_st->st_ex_uid));
347 if (cookie_st->st_ex_gid != fsp_st->st_ex_gid) {
348 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
349 "stat_ex.%s differs: "
350 "cookie:%llu != stat:%llu, "
351 "denying durable reconnect\n",
354 (unsigned long long)cookie_st->st_ex_gid,
355 (unsigned long long)fsp_st->st_ex_gid));
359 if (cookie_st->st_ex_rdev != fsp_st->st_ex_rdev) {
360 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
361 "stat_ex.%s differs: "
362 "cookie:%llu != stat:%llu, "
363 "denying durable reconnect\n",
366 (unsigned long long)cookie_st->st_ex_rdev,
367 (unsigned long long)fsp_st->st_ex_rdev));
371 if (cookie_st->st_ex_size != fsp_st->st_ex_size) {
372 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
373 "stat_ex.%s differs: "
374 "cookie:%llu != stat:%llu, "
375 "denying durable reconnect\n",
378 (unsigned long long)cookie_st->st_ex_size,
379 (unsigned long long)fsp_st->st_ex_size));
383 ret = timespec_compare(&cookie_st->st_ex_atime,
384 &fsp_st->st_ex_atime);
386 struct timeval tc, ts;
387 tc = convert_timespec_to_timeval(cookie_st->st_ex_atime);
388 ts = convert_timespec_to_timeval(fsp_st->st_ex_atime);
390 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
391 "stat_ex.%s differs: "
392 "cookie:'%s' != stat:'%s', "
393 "denying durable reconnect\n",
396 timeval_string(talloc_tos(), &tc, true),
397 timeval_string(talloc_tos(), &ts, true)));
401 ret = timespec_compare(&cookie_st->st_ex_mtime,
402 &fsp_st->st_ex_mtime);
404 struct timeval tc, ts;
405 tc = convert_timespec_to_timeval(cookie_st->st_ex_mtime);
406 ts = convert_timespec_to_timeval(fsp_st->st_ex_mtime);
408 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
409 "stat_ex.%s differs: "
410 "cookie:'%s' != stat:'%s', "
411 "denying durable reconnect\n",
414 timeval_string(talloc_tos(), &tc, true),
415 timeval_string(talloc_tos(), &ts, true)));
419 ret = timespec_compare(&cookie_st->st_ex_ctime,
420 &fsp_st->st_ex_ctime);
422 struct timeval tc, ts;
423 tc = convert_timespec_to_timeval(cookie_st->st_ex_ctime);
424 ts = convert_timespec_to_timeval(fsp_st->st_ex_ctime);
426 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
427 "stat_ex.%s differs: "
428 "cookie:'%s' != stat:'%s', "
429 "denying durable reconnect\n",
432 timeval_string(talloc_tos(), &tc, true),
433 timeval_string(talloc_tos(), &ts, true)));
437 ret = timespec_compare(&cookie_st->st_ex_btime,
438 &fsp_st->st_ex_btime);
440 struct timeval tc, ts;
441 tc = convert_timespec_to_timeval(cookie_st->st_ex_btime);
442 ts = convert_timespec_to_timeval(fsp_st->st_ex_btime);
444 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
445 "stat_ex.%s differs: "
446 "cookie:'%s' != stat:'%s', "
447 "denying durable reconnect\n",
450 timeval_string(talloc_tos(), &tc, true),
451 timeval_string(talloc_tos(), &ts, true)));
455 if (cookie_st->st_ex_iflags != fsp_st->st_ex_iflags) {
456 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
457 "stat_ex.%s differs: "
458 "cookie:%llu != stat:%llu, "
459 "denying durable reconnect\n",
461 "st_ex_calculated_birthtime",
462 (unsigned long long)cookie_st->st_ex_iflags,
463 (unsigned long long)fsp_st->st_ex_iflags));
467 if (cookie_st->st_ex_blksize != fsp_st->st_ex_blksize) {
468 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
469 "stat_ex.%s differs: "
470 "cookie:%llu != stat:%llu, "
471 "denying durable reconnect\n",
474 (unsigned long long)cookie_st->st_ex_blksize,
475 (unsigned long long)fsp_st->st_ex_blksize));
479 if (cookie_st->st_ex_blocks != fsp_st->st_ex_blocks) {
480 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
481 "stat_ex.%s differs: "
482 "cookie:%llu != stat:%llu, "
483 "denying durable reconnect\n",
486 (unsigned long long)cookie_st->st_ex_blocks,
487 (unsigned long long)fsp_st->st_ex_blocks));
491 if (cookie_st->st_ex_flags != fsp_st->st_ex_flags) {
492 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
493 "stat_ex.%s differs: "
494 "cookie:%llu != stat:%llu, "
495 "denying durable reconnect\n",
498 (unsigned long long)cookie_st->st_ex_flags,
499 (unsigned long long)fsp_st->st_ex_flags));
506 static bool durable_reconnect_fn(
507 struct share_mode_entry *e,
511 struct share_mode_entry *dst_e = private_data;
513 if (dst_e->pid.pid != 0) {
514 DBG_INFO("Found more than one entry, invalidating previous\n");
516 return true; /* end the loop through share mode entries */
519 return false; /* Look at potential other entries */
522 NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
523 struct smb_request *smb1req,
524 struct smbXsrv_open *op,
525 const DATA_BLOB old_cookie,
527 files_struct **result,
528 DATA_BLOB *new_cookie)
530 const struct loadparm_substitution *lp_sub =
531 loadparm_s3_global_substitution();
532 struct share_mode_lock *lck;
533 struct share_mode_entry e;
534 struct files_struct *fsp = NULL;
539 struct file_id file_id;
540 struct smb_filename *smb_fname = NULL;
541 enum ndr_err_code ndr_err;
542 struct vfs_default_durable_cookie cookie;
543 DATA_BLOB new_cookie_blob = data_blob_null;
546 *new_cookie = data_blob_null;
548 if (!lp_durable_handles(SNUM(conn))) {
549 return NT_STATUS_NOT_SUPPORTED;
553 * the checks for kernel oplocks
554 * and similar things are done
555 * in the vfs_default_durable_cookie()
559 ndr_err = ndr_pull_struct_blob_all(
563 (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
564 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
565 status = ndr_map_error2ntstatus(ndr_err);
569 if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
570 return NT_STATUS_INVALID_PARAMETER;
573 if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
574 return NT_STATUS_INVALID_PARAMETER;
577 if (!cookie.allow_reconnect) {
578 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
581 if (strcmp(cookie.servicepath, conn->connectpath) != 0) {
582 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
585 /* Create an smb_filename with stream_name == NULL. */
586 smb_fname = synthetic_smb_fname(talloc_tos(),
591 if (smb_fname == NULL) {
592 return NT_STATUS_NO_MEMORY;
595 ret = SMB_VFS_LSTAT(conn, smb_fname);
597 status = map_nt_error_from_unix_common(errno);
598 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
599 smb_fname_str_dbg(smb_fname),
604 if (!S_ISREG(smb_fname->st.st_ex_mode)) {
605 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
608 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
609 if (!file_id_equal(&cookie.id, &file_id)) {
610 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
614 * 1. check entry in locking.tdb
617 lck = get_existing_share_mode_lock(mem_ctx, file_id);
619 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
620 "not obtained from db\n"));
621 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
624 e = (struct share_mode_entry) { .pid.pid = 0 };
626 ok = share_mode_forall_entries(lck, durable_reconnect_fn, &e);
628 DBG_WARNING("share_mode_forall_entries failed\n");
630 return NT_STATUS_INTERNAL_DB_ERROR;
633 if (e.pid.pid == 0) {
634 DBG_WARNING("Did not find a unique valid share mode entry\n");
636 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
639 if (!server_id_is_disconnected(&e.pid)) {
640 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
641 "reconnect for handle that was not marked "
642 "disconnected (e.g. smbd or cluster node died)\n"));
644 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
647 if (e.share_file_id != op->global->open_persistent_id) {
648 DBG_INFO("denying durable "
649 "share_file_id changed %"PRIu64" != %"PRIu64" "
650 "(e.g. another client had opened the file)\n",
652 op->global->open_persistent_id);
654 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
657 if ((e.access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
660 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
661 "share[%s] is not writeable anymore\n",
662 lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
664 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
668 * 2. proceed with opening file
671 status = fsp_new(conn, conn, &fsp);
672 if (!NT_STATUS_IS_OK(status)) {
673 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
674 "new fsp: %s\n", nt_errstr(status)));
679 fsp->fh->private_options = e.private_options;
680 fsp->file_id = file_id;
681 fsp->file_pid = smb1req->smbpid;
682 fsp->vuid = smb1req->vuid;
683 fsp->open_time = e.time;
684 fsp->access_mask = e.access_mask;
685 fsp->fsp_flags.can_read = ((fsp->access_mask & FILE_READ_DATA) != 0);
686 fsp->fsp_flags.can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
687 fsp->fnum = op->local_id;
692 * Do we need to store the modified flag in the DB?
694 fsp->fsp_flags.modified = false;
696 * no durables for directories
698 fsp->is_directory = false;
700 * For normal files, can_lock == !is_directory
702 fsp->fsp_flags.can_lock = true;
704 * We do not support aio write behind for smb2
706 fsp->aio_write_behind = false;
707 fsp->oplock_type = e.op_type;
709 if (fsp->oplock_type == LEASE_OPLOCK) {
710 uint32_t current_state;
711 uint16_t lease_version, epoch;
714 * Ensure the existing client guid matches the
715 * stored one in the share_mode_entry.
717 if (!GUID_equal(fsp_client_guid(fsp),
721 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
724 status = leases_db_get(
728 ¤t_state, /* current_state */
730 NULL, /* breaking_to_requested */
731 NULL, /* breaking_to_required */
732 &lease_version, /* lease_version */
734 if (!NT_STATUS_IS_OK(status)) {
740 fsp->lease = find_fsp_lease(
746 if (fsp->lease == NULL) {
749 return NT_STATUS_NO_MEMORY;
753 fsp->initial_allocation_size = cookie.initial_allocation_size;
754 fsp->fh->position_information = cookie.position_information;
755 fsp->fsp_flags.update_write_time_triggered =
756 cookie.update_write_time_triggered;
757 fsp->fsp_flags.update_write_time_on_close =
758 cookie.update_write_time_on_close;
759 fsp->fsp_flags.write_time_forced = cookie.write_time_forced;
760 fsp->close_write_time = nt_time_to_full_timespec(
761 cookie.close_write_time);
763 status = fsp_set_smb_fname(fsp, smb_fname);
764 if (!NT_STATUS_IS_OK(status)) {
767 DEBUG(0, ("vfs_default_durable_reconnect: "
768 "fsp_set_smb_fname failed: %s\n",
776 ok = reset_share_mode_entry(
780 messaging_server_id(conn->sconn->msg_ctx),
784 DBG_DEBUG("Could not set new share_mode_entry values\n");
788 return NT_STATUS_INTERNAL_ERROR;
791 ok = brl_reconnect_disconnected(fsp);
793 status = NT_STATUS_INTERNAL_ERROR;
794 DEBUG(1, ("vfs_default_durable_reconnect: "
795 "failed to reopen brlocks: %s\n",
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) {
810 } else if (fsp->fsp_flags.can_read) {
814 status = fd_open(conn, fsp, flags, 0 /* mode */);
815 if (!NT_STATUS_IS_OK(status)) {
817 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
818 "file: %s\n", nt_errstr(status)));
825 * We now check the stat info stored in the cookie against
826 * the current stat data from the file we just opened.
827 * If any detail differs, we deny the durable reconnect,
828 * because in that case it is very likely that someone
829 * opened the file while the handle was disconnected,
830 * which has to be interpreted as an oplock break.
833 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
835 status = map_nt_error_from_unix_common(errno);
836 DEBUG(1, ("Unable to fstat stream: %s => %s\n",
837 smb_fname_str_dbg(smb_fname),
839 ret = SMB_VFS_CLOSE(fsp);
841 DEBUG(0, ("vfs_default_durable_reconnect: "
842 "SMB_VFS_CLOSE failed (%s) - leaking file "
843 "descriptor\n", strerror(errno)));
851 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
852 ret = SMB_VFS_CLOSE(fsp);
854 DEBUG(0, ("vfs_default_durable_reconnect: "
855 "SMB_VFS_CLOSE failed (%s) - leaking file "
856 "descriptor\n", strerror(errno)));
861 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
864 file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
865 if (!file_id_equal(&cookie.id, &file_id)) {
866 ret = SMB_VFS_CLOSE(fsp);
868 DEBUG(0, ("vfs_default_durable_reconnect: "
869 "SMB_VFS_CLOSE failed (%s) - leaking file "
870 "descriptor\n", strerror(errno)));
875 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
878 (void)dos_mode(fsp->conn, fsp->fsp_name);
880 ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info,
884 ret = SMB_VFS_CLOSE(fsp);
886 DEBUG(0, ("vfs_default_durable_reconnect: "
887 "SMB_VFS_CLOSE failed (%s) - leaking file "
888 "descriptor\n", strerror(errno)));
893 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
896 status = set_file_oplock(fsp);
897 if (!NT_STATUS_IS_OK(status)) {
898 DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
899 "after opening file: %s\n", nt_errstr(status)));
900 ret = SMB_VFS_CLOSE(fsp);
902 DEBUG(0, ("vfs_default_durable_reconnect: "
903 "SMB_VFS_CLOSE failed (%s) - leaking file "
904 "descriptor\n", strerror(errno)));
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",
923 smb1req->chain_fsp = fsp;
924 smb1req->smb2req->compat_chain_fsp = fsp;
926 DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
930 * release the sharemode lock: this writes the changes
932 lck->data->modified = true;
936 *new_cookie = new_cookie_blob;