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"
34 NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
36 DATA_BLOB *cookie_blob)
38 struct connection_struct *conn = fsp->conn;
39 enum ndr_err_code ndr_err;
40 struct vfs_default_durable_cookie cookie;
42 if (!lp_durable_handles(SNUM(conn))) {
43 return NT_STATUS_NOT_SUPPORTED;
46 if (lp_kernel_share_modes(SNUM(conn))) {
48 * We do not support durable handles
49 * if kernel share modes (flocks) are used
51 return NT_STATUS_NOT_SUPPORTED;
54 if (lp_kernel_oplocks(SNUM(conn))) {
56 * We do not support durable handles
57 * if kernel oplocks are used
59 return NT_STATUS_NOT_SUPPORTED;
62 if ((fsp->current_lock_count > 0) &&
63 lp_posix_locking(fsp->conn->params))
66 * We do not support durable handles
67 * if the handle has posix locks.
69 return NT_STATUS_NOT_SUPPORTED;
72 if (fsp->is_directory) {
73 return NT_STATUS_NOT_SUPPORTED;
76 if (fsp->fh->fd == -1) {
77 return NT_STATUS_NOT_SUPPORTED;
80 if (is_ntfs_stream_smb_fname(fsp->fsp_name)) {
82 * We do not support durable handles
85 return NT_STATUS_NOT_SUPPORTED;
88 if (is_fake_file(fsp->fsp_name)) {
90 * We do not support durable handles
93 return NT_STATUS_NOT_SUPPORTED;
97 cookie.allow_reconnect = false;
98 cookie.id = fsp->file_id;
99 cookie.servicepath = conn->connectpath;
100 cookie.base_name = fsp->fsp_name->base_name;
101 cookie.initial_allocation_size = fsp->initial_allocation_size;
102 cookie.position_information = fsp->fh->position_information;
103 cookie.update_write_time_triggered = fsp->update_write_time_triggered;
104 cookie.update_write_time_on_close = fsp->update_write_time_on_close;
105 cookie.write_time_forced = fsp->write_time_forced;
106 cookie.close_write_time = fsp->close_write_time;
108 cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
109 cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
110 cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
111 cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
112 cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
113 cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
114 cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
115 cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
116 cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
117 cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
118 cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
119 cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
120 cookie.stat_info.st_ex_calculated_birthtime = fsp->fsp_name->st.st_ex_calculated_birthtime;
121 cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
122 cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
123 cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
124 cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
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->initial_delete_on_close) {
181 return NT_STATUS_NOT_SUPPORTED;
183 if (fsp->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;
210 if (fsp->write_time_forced) {
211 ft.mtime = lck->data->changed_write_time;
212 } else if (fsp->update_write_time_on_close) {
213 if (null_timespec(fsp->close_write_time)) {
214 ft.mtime = timespec_current();
216 ft.mtime = fsp->close_write_time;
220 if (!null_timespec(ft.mtime)) {
221 round_timespec(conn->ts_res, &ft.mtime);
222 file_ntimes(conn, fsp->fsp_name, &ft);
225 ok = mark_share_mode_disconnected(lck, fsp);
231 ok = brl_mark_disconnected(fsp);
237 return NT_STATUS_NOT_SUPPORTED;
241 status = vfs_stat_fsp(fsp);
242 if (!NT_STATUS_IS_OK(status)) {
247 cookie.allow_reconnect = true;
248 cookie.id = fsp->file_id;
249 cookie.servicepath = conn->connectpath;
250 cookie.base_name = fsp->fsp_name->base_name;
251 cookie.initial_allocation_size = fsp->initial_allocation_size;
252 cookie.position_information = fsp->fh->position_information;
253 cookie.update_write_time_triggered = fsp->update_write_time_triggered;
254 cookie.update_write_time_on_close = fsp->update_write_time_on_close;
255 cookie.write_time_forced = fsp->write_time_forced;
256 cookie.close_write_time = fsp->close_write_time;
258 cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
259 cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
260 cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
261 cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
262 cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
263 cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
264 cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
265 cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
266 cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
267 cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
268 cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
269 cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
270 cookie.stat_info.st_ex_calculated_birthtime = fsp->fsp_name->st.st_ex_calculated_birthtime;
271 cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
272 cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
273 cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
274 cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
276 ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
277 (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
278 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
279 status = ndr_map_error2ntstatus(ndr_err);
283 status = fd_close(fsp);
284 if (!NT_STATUS_IS_OK(status)) {
285 data_blob_free(&new_cookie_blob);
289 *new_cookie = new_cookie_blob;
295 * Check whether a cookie-stored struct info is the same
296 * as a given SMB_STRUCT_STAT, as coming with the fsp.
298 static bool vfs_default_durable_reconnect_check_stat(
299 struct vfs_default_durable_stat *cookie_st,
300 SMB_STRUCT_STAT *fsp_st,
305 if (cookie_st->st_ex_mode != fsp_st->st_ex_mode) {
306 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
307 "stat_ex.%s differs: "
308 "cookie:%llu != stat:%llu, "
309 "denying durable reconnect\n",
312 (unsigned long long)cookie_st->st_ex_mode,
313 (unsigned long long)fsp_st->st_ex_mode));
317 if (cookie_st->st_ex_nlink != fsp_st->st_ex_nlink) {
318 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
319 "stat_ex.%s differs: "
320 "cookie:%llu != stat:%llu, "
321 "denying durable reconnect\n",
324 (unsigned long long)cookie_st->st_ex_nlink,
325 (unsigned long long)fsp_st->st_ex_nlink));
329 if (cookie_st->st_ex_uid != fsp_st->st_ex_uid) {
330 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
331 "stat_ex.%s differs: "
332 "cookie:%llu != stat:%llu, "
333 "denying durable reconnect\n",
336 (unsigned long long)cookie_st->st_ex_uid,
337 (unsigned long long)fsp_st->st_ex_uid));
341 if (cookie_st->st_ex_gid != fsp_st->st_ex_gid) {
342 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
343 "stat_ex.%s differs: "
344 "cookie:%llu != stat:%llu, "
345 "denying durable reconnect\n",
348 (unsigned long long)cookie_st->st_ex_gid,
349 (unsigned long long)fsp_st->st_ex_gid));
353 if (cookie_st->st_ex_rdev != fsp_st->st_ex_rdev) {
354 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
355 "stat_ex.%s differs: "
356 "cookie:%llu != stat:%llu, "
357 "denying durable reconnect\n",
360 (unsigned long long)cookie_st->st_ex_rdev,
361 (unsigned long long)fsp_st->st_ex_rdev));
365 if (cookie_st->st_ex_size != fsp_st->st_ex_size) {
366 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
367 "stat_ex.%s differs: "
368 "cookie:%llu != stat:%llu, "
369 "denying durable reconnect\n",
372 (unsigned long long)cookie_st->st_ex_size,
373 (unsigned long long)fsp_st->st_ex_size));
377 ret = timespec_compare(&cookie_st->st_ex_atime,
378 &fsp_st->st_ex_atime);
380 struct timeval tc, ts;
381 tc = convert_timespec_to_timeval(cookie_st->st_ex_atime);
382 ts = convert_timespec_to_timeval(fsp_st->st_ex_atime);
384 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
385 "stat_ex.%s differs: "
386 "cookie:'%s' != stat:'%s', "
387 "denying durable reconnect\n",
390 timeval_string(talloc_tos(), &tc, true),
391 timeval_string(talloc_tos(), &ts, true)));
395 ret = timespec_compare(&cookie_st->st_ex_mtime,
396 &fsp_st->st_ex_mtime);
398 struct timeval tc, ts;
399 tc = convert_timespec_to_timeval(cookie_st->st_ex_mtime);
400 ts = convert_timespec_to_timeval(fsp_st->st_ex_mtime);
402 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
403 "stat_ex.%s differs: "
404 "cookie:'%s' != stat:'%s', "
405 "denying durable reconnect\n",
408 timeval_string(talloc_tos(), &tc, true),
409 timeval_string(talloc_tos(), &ts, true)));
413 ret = timespec_compare(&cookie_st->st_ex_ctime,
414 &fsp_st->st_ex_ctime);
416 struct timeval tc, ts;
417 tc = convert_timespec_to_timeval(cookie_st->st_ex_ctime);
418 ts = convert_timespec_to_timeval(fsp_st->st_ex_ctime);
420 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
421 "stat_ex.%s differs: "
422 "cookie:'%s' != stat:'%s', "
423 "denying durable reconnect\n",
426 timeval_string(talloc_tos(), &tc, true),
427 timeval_string(talloc_tos(), &ts, true)));
431 ret = timespec_compare(&cookie_st->st_ex_btime,
432 &fsp_st->st_ex_btime);
434 struct timeval tc, ts;
435 tc = convert_timespec_to_timeval(cookie_st->st_ex_btime);
436 ts = convert_timespec_to_timeval(fsp_st->st_ex_btime);
438 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
439 "stat_ex.%s differs: "
440 "cookie:'%s' != stat:'%s', "
441 "denying durable reconnect\n",
444 timeval_string(talloc_tos(), &tc, true),
445 timeval_string(talloc_tos(), &ts, true)));
449 if (cookie_st->st_ex_calculated_birthtime !=
450 fsp_st->st_ex_calculated_birthtime)
452 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
453 "stat_ex.%s differs: "
454 "cookie:%llu != stat:%llu, "
455 "denying durable reconnect\n",
457 "st_ex_calculated_birthtime",
458 (unsigned long long)cookie_st->st_ex_calculated_birthtime,
459 (unsigned long long)fsp_st->st_ex_calculated_birthtime));
463 if (cookie_st->st_ex_blksize != fsp_st->st_ex_blksize) {
464 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
465 "stat_ex.%s differs: "
466 "cookie:%llu != stat:%llu, "
467 "denying durable reconnect\n",
470 (unsigned long long)cookie_st->st_ex_blksize,
471 (unsigned long long)fsp_st->st_ex_blksize));
475 if (cookie_st->st_ex_blocks != fsp_st->st_ex_blocks) {
476 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
477 "stat_ex.%s differs: "
478 "cookie:%llu != stat:%llu, "
479 "denying durable reconnect\n",
482 (unsigned long long)cookie_st->st_ex_blocks,
483 (unsigned long long)fsp_st->st_ex_blocks));
487 if (cookie_st->st_ex_flags != fsp_st->st_ex_flags) {
488 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
489 "stat_ex.%s differs: "
490 "cookie:%llu != stat:%llu, "
491 "denying durable reconnect\n",
494 (unsigned long long)cookie_st->st_ex_flags,
495 (unsigned long long)fsp_st->st_ex_flags));
499 if (cookie_st->st_ex_mask != fsp_st->st_ex_mask) {
500 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
501 "stat_ex.%s differs: "
502 "cookie:%llu != stat:%llu, "
503 "denying durable reconnect\n",
506 (unsigned long long)cookie_st->st_ex_mask,
507 (unsigned long long)fsp_st->st_ex_mask));
514 NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
515 struct smb_request *smb1req,
516 struct smbXsrv_open *op,
517 const DATA_BLOB old_cookie,
519 files_struct **result,
520 DATA_BLOB *new_cookie)
522 struct share_mode_lock *lck;
523 struct share_mode_entry *e;
524 struct files_struct *fsp = NULL;
529 struct file_id file_id;
530 struct smb_filename *smb_fname = NULL;
531 enum ndr_err_code ndr_err;
532 struct vfs_default_durable_cookie cookie;
533 DATA_BLOB new_cookie_blob = data_blob_null;
536 *new_cookie = data_blob_null;
538 if (!lp_durable_handles(SNUM(conn))) {
539 return NT_STATUS_NOT_SUPPORTED;
543 * the checks for kernel oplocks
544 * and similar things are done
545 * in the vfs_default_durable_cookie()
549 ndr_err = ndr_pull_struct_blob_all(
553 (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
554 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
555 status = ndr_map_error2ntstatus(ndr_err);
559 if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
560 return NT_STATUS_INVALID_PARAMETER;
563 if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
564 return NT_STATUS_INVALID_PARAMETER;
567 if (!cookie.allow_reconnect) {
568 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
571 if (strcmp(cookie.servicepath, conn->connectpath) != 0) {
572 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
575 /* Create an smb_filename with stream_name == NULL. */
576 smb_fname = synthetic_smb_fname(talloc_tos(),
581 if (smb_fname == NULL) {
582 return NT_STATUS_NO_MEMORY;
585 ret = SMB_VFS_LSTAT(conn, smb_fname);
587 status = map_nt_error_from_unix_common(errno);
588 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
589 smb_fname_str_dbg(smb_fname),
594 if (!S_ISREG(smb_fname->st.st_ex_mode)) {
595 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
598 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
599 if (!file_id_equal(&cookie.id, &file_id)) {
600 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
604 * 1. check entry in locking.tdb
607 lck = get_existing_share_mode_lock(mem_ctx, file_id);
609 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
610 "not obtained from db\n"));
611 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
614 if (lck->data->num_share_modes == 0) {
615 DEBUG(1, ("vfs_default_durable_reconnect: Error: no share-mode "
616 "entry in existing share mode lock\n"));
618 return NT_STATUS_INTERNAL_DB_ERROR;
621 if (lck->data->num_share_modes > 1) {
623 * It can't be durable if there is more than one handle
626 DEBUG(5, ("vfs_default_durable_reconnect: more than one "
627 "share-mode entry - can not be durable\n"));
629 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
632 e = &lck->data->share_modes[0];
634 if (!server_id_is_disconnected(&e->pid)) {
635 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
636 "reconnect for handle that was not marked "
637 "disconnected (e.g. smbd or cluster node died)\n"));
639 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
642 if (e->share_file_id != op->global->open_persistent_id) {
643 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
644 "share_file_id changed %llu != %llu"
645 "(e.g. another client had opened the file)\n",
646 (unsigned long long)e->share_file_id,
647 (unsigned long long)op->global->open_persistent_id));
649 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
652 if ((e->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
655 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
656 "share[%s] is not writeable anymore\n",
657 lp_servicename(talloc_tos(), SNUM(conn))));
659 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
663 * 2. proceed with opening file
666 status = fsp_new(conn, conn, &fsp);
667 if (!NT_STATUS_IS_OK(status)) {
668 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
669 "new fsp: %s\n", nt_errstr(status)));
674 fsp->fh->private_options = e->private_options;
675 fsp->fh->gen_id = smbXsrv_open_hash(op);
676 fsp->file_id = file_id;
677 fsp->file_pid = smb1req->smbpid;
678 fsp->vuid = smb1req->vuid;
679 fsp->open_time = e->time;
680 fsp->access_mask = e->access_mask;
681 fsp->share_access = e->share_access;
682 fsp->can_read = ((fsp->access_mask & (FILE_READ_DATA)) != 0);
683 fsp->can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
684 fsp->fnum = op->local_id;
688 * Do we need to store the modified flag in the DB?
690 fsp->modified = false;
692 * no durables for directories
694 fsp->is_directory = false;
696 * For normal files, can_lock == !is_directory
698 fsp->can_lock = true;
700 * We do not support aio write behind for smb2
702 fsp->aio_write_behind = false;
703 fsp->oplock_type = e->op_type;
705 if (fsp->oplock_type == LEASE_OPLOCK) {
706 struct share_mode_lease *l = &lck->data->leases[e->lease_idx];
707 struct smb2_lease_key key;
709 key.data[0] = l->lease_key.data[0];
710 key.data[1] = l->lease_key.data[1];
712 fsp->lease = find_fsp_lease(fsp, &key, l);
713 if (fsp->lease == NULL) {
716 return NT_STATUS_NO_MEMORY;
720 * Ensure the existing client guid matches the
721 * stored one in the share_mode_lease.
723 if (!GUID_equal(fsp_client_guid(fsp),
727 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
731 fsp->initial_allocation_size = cookie.initial_allocation_size;
732 fsp->fh->position_information = cookie.position_information;
733 fsp->update_write_time_triggered = cookie.update_write_time_triggered;
734 fsp->update_write_time_on_close = cookie.update_write_time_on_close;
735 fsp->write_time_forced = cookie.write_time_forced;
736 fsp->close_write_time = cookie.close_write_time;
738 status = fsp_set_smb_fname(fsp, smb_fname);
739 if (!NT_STATUS_IS_OK(status)) {
742 DEBUG(0, ("vfs_default_durable_reconnect: "
743 "fsp_set_smb_fname failed: %s\n",
751 e->pid = messaging_server_id(conn->sconn->msg_ctx);
752 e->op_mid = smb1req->mid;
753 e->share_file_id = fsp->fh->gen_id;
755 ok = brl_reconnect_disconnected(fsp);
757 status = NT_STATUS_INTERNAL_ERROR;
758 DEBUG(1, ("vfs_default_durable_reconnect: "
759 "failed to reopen brlocks: %s\n",
768 * TODO: properly calculate open flags
770 if (fsp->can_write && fsp->can_read) {
772 } else if (fsp->can_write) {
774 } else if (fsp->can_read) {
778 status = fd_open(conn, fsp, flags, 0 /* mode */);
779 if (!NT_STATUS_IS_OK(status)) {
781 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
782 "file: %s\n", nt_errstr(status)));
789 * We now check the stat info stored in the cookie against
790 * the current stat data from the file we just opened.
791 * If any detail differs, we deny the durable reconnect,
792 * because in that case it is very likely that someone
793 * opened the file while the handle was disconnected,
794 * which has to be interpreted as an oplock break.
797 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
799 status = map_nt_error_from_unix_common(errno);
800 DEBUG(1, ("Unable to fstat stream: %s => %s\n",
801 smb_fname_str_dbg(smb_fname),
803 ret = SMB_VFS_CLOSE(fsp);
805 DEBUG(0, ("vfs_default_durable_reconnect: "
806 "SMB_VFS_CLOSE failed (%s) - leaking file "
807 "descriptor\n", strerror(errno)));
815 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
816 ret = SMB_VFS_CLOSE(fsp);
818 DEBUG(0, ("vfs_default_durable_reconnect: "
819 "SMB_VFS_CLOSE failed (%s) - leaking file "
820 "descriptor\n", strerror(errno)));
825 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
828 file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
829 if (!file_id_equal(&cookie.id, &file_id)) {
830 ret = SMB_VFS_CLOSE(fsp);
832 DEBUG(0, ("vfs_default_durable_reconnect: "
833 "SMB_VFS_CLOSE failed (%s) - leaking file "
834 "descriptor\n", strerror(errno)));
839 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
842 ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info,
846 ret = SMB_VFS_CLOSE(fsp);
848 DEBUG(0, ("vfs_default_durable_reconnect: "
849 "SMB_VFS_CLOSE failed (%s) - leaking file "
850 "descriptor\n", strerror(errno)));
855 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
858 status = set_file_oplock(fsp);
859 if (!NT_STATUS_IS_OK(status)) {
860 DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
861 "after opening file: %s\n", nt_errstr(status)));
862 ret = SMB_VFS_CLOSE(fsp);
864 DEBUG(0, ("vfs_default_durable_reconnect: "
865 "SMB_VFS_CLOSE failed (%s) - leaking file "
866 "descriptor\n", strerror(errno)));
874 status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob);
875 if (!NT_STATUS_IS_OK(status)) {
877 DEBUG(1, ("vfs_default_durable_reconnect: "
878 "vfs_default_durable_cookie - %s\n",
885 smb1req->chain_fsp = fsp;
886 smb1req->smb2req->compat_chain_fsp = fsp;
888 DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
892 * release the sharemode lock: this writes the changes
894 lck->data->modified = true;
898 *new_cookie = new_cookie_blob;