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 update_write_time_handler(fsp
->conn
->sconn
->ev_ctx
,
198 fsp
->update_write_time_event
,
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
;
213 if (fsp
->write_time_forced
) {
214 ft
.mtime
= lck
->data
->changed_write_time
;
215 } else if (fsp
->update_write_time_on_close
) {
216 if (null_timespec(fsp
->close_write_time
)) {
217 ft
.mtime
= timespec_current();
219 ft
.mtime
= fsp
->close_write_time
;
223 if (!null_timespec(ft
.mtime
)) {
224 round_timespec(conn
->ts_res
, &ft
.mtime
);
225 file_ntimes(conn
, fsp
->fsp_name
, &ft
);
228 ok
= mark_share_mode_disconnected(lck
, fsp
);
234 ok
= brl_mark_disconnected(fsp
);
240 return NT_STATUS_NOT_SUPPORTED
;
244 status
= vfs_stat_fsp(fsp
);
245 if (!NT_STATUS_IS_OK(status
)) {
250 cookie
.allow_reconnect
= true;
251 cookie
.id
= fsp
->file_id
;
252 cookie
.servicepath
= conn
->connectpath
;
253 cookie
.base_name
= fsp
->fsp_name
->base_name
;
254 cookie
.initial_allocation_size
= fsp
->initial_allocation_size
;
255 cookie
.position_information
= fsp
->fh
->position_information
;
256 cookie
.update_write_time_triggered
= fsp
->update_write_time_triggered
;
257 cookie
.update_write_time_on_close
= fsp
->update_write_time_on_close
;
258 cookie
.write_time_forced
= fsp
->write_time_forced
;
259 cookie
.close_write_time
= fsp
->close_write_time
;
261 cookie
.stat_info
.st_ex_dev
= fsp
->fsp_name
->st
.st_ex_dev
;
262 cookie
.stat_info
.st_ex_ino
= fsp
->fsp_name
->st
.st_ex_ino
;
263 cookie
.stat_info
.st_ex_mode
= fsp
->fsp_name
->st
.st_ex_mode
;
264 cookie
.stat_info
.st_ex_nlink
= fsp
->fsp_name
->st
.st_ex_nlink
;
265 cookie
.stat_info
.st_ex_uid
= fsp
->fsp_name
->st
.st_ex_uid
;
266 cookie
.stat_info
.st_ex_gid
= fsp
->fsp_name
->st
.st_ex_gid
;
267 cookie
.stat_info
.st_ex_rdev
= fsp
->fsp_name
->st
.st_ex_rdev
;
268 cookie
.stat_info
.st_ex_size
= fsp
->fsp_name
->st
.st_ex_size
;
269 cookie
.stat_info
.st_ex_atime
= fsp
->fsp_name
->st
.st_ex_atime
;
270 cookie
.stat_info
.st_ex_mtime
= fsp
->fsp_name
->st
.st_ex_mtime
;
271 cookie
.stat_info
.st_ex_ctime
= fsp
->fsp_name
->st
.st_ex_ctime
;
272 cookie
.stat_info
.st_ex_btime
= fsp
->fsp_name
->st
.st_ex_btime
;
273 cookie
.stat_info
.st_ex_calculated_birthtime
= fsp
->fsp_name
->st
.st_ex_calculated_birthtime
;
274 cookie
.stat_info
.st_ex_blksize
= fsp
->fsp_name
->st
.st_ex_blksize
;
275 cookie
.stat_info
.st_ex_blocks
= fsp
->fsp_name
->st
.st_ex_blocks
;
276 cookie
.stat_info
.st_ex_flags
= fsp
->fsp_name
->st
.st_ex_flags
;
277 cookie
.stat_info
.st_ex_mask
= fsp
->fsp_name
->st
.st_ex_mask
;
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_dev
!= fsp_st
->st_ex_dev
) {
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_dev
,
316 (unsigned long long)fsp_st
->st_ex_dev
));
320 if (cookie_st
->st_ex_ino
!= fsp_st
->st_ex_ino
) {
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_ino
,
328 (unsigned long long)fsp_st
->st_ex_ino
));
332 if (cookie_st
->st_ex_mode
!= fsp_st
->st_ex_mode
) {
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_mode
,
340 (unsigned long long)fsp_st
->st_ex_mode
));
344 if (cookie_st
->st_ex_nlink
!= fsp_st
->st_ex_nlink
) {
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_nlink
,
352 (unsigned long long)fsp_st
->st_ex_nlink
));
356 if (cookie_st
->st_ex_uid
!= fsp_st
->st_ex_uid
) {
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_uid
,
364 (unsigned long long)fsp_st
->st_ex_uid
));
368 if (cookie_st
->st_ex_gid
!= fsp_st
->st_ex_gid
) {
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_gid
,
376 (unsigned long long)fsp_st
->st_ex_gid
));
380 if (cookie_st
->st_ex_rdev
!= fsp_st
->st_ex_rdev
) {
381 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
382 "stat_ex.%s differs: "
383 "cookie:%llu != stat:%llu, "
384 "denying durable reconnect\n",
387 (unsigned long long)cookie_st
->st_ex_rdev
,
388 (unsigned long long)fsp_st
->st_ex_rdev
));
392 if (cookie_st
->st_ex_size
!= fsp_st
->st_ex_size
) {
393 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
394 "stat_ex.%s differs: "
395 "cookie:%llu != stat:%llu, "
396 "denying durable reconnect\n",
399 (unsigned long long)cookie_st
->st_ex_size
,
400 (unsigned long long)fsp_st
->st_ex_size
));
404 ret
= timespec_compare(&cookie_st
->st_ex_atime
,
405 &fsp_st
->st_ex_atime
);
407 struct timeval tc
, ts
;
408 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_atime
);
409 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_atime
);
411 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
412 "stat_ex.%s differs: "
413 "cookie:'%s' != stat:'%s', "
414 "denying durable reconnect\n",
417 timeval_string(talloc_tos(), &tc
, true),
418 timeval_string(talloc_tos(), &ts
, true)));
422 ret
= timespec_compare(&cookie_st
->st_ex_mtime
,
423 &fsp_st
->st_ex_mtime
);
425 struct timeval tc
, ts
;
426 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_mtime
);
427 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_mtime
);
429 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
430 "stat_ex.%s differs: "
431 "cookie:'%s' != stat:'%s', "
432 "denying durable reconnect\n",
435 timeval_string(talloc_tos(), &tc
, true),
436 timeval_string(talloc_tos(), &ts
, true)));
440 ret
= timespec_compare(&cookie_st
->st_ex_ctime
,
441 &fsp_st
->st_ex_ctime
);
443 struct timeval tc
, ts
;
444 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_ctime
);
445 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_ctime
);
447 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
448 "stat_ex.%s differs: "
449 "cookie:'%s' != stat:'%s', "
450 "denying durable reconnect\n",
453 timeval_string(talloc_tos(), &tc
, true),
454 timeval_string(talloc_tos(), &ts
, true)));
458 ret
= timespec_compare(&cookie_st
->st_ex_btime
,
459 &fsp_st
->st_ex_btime
);
461 struct timeval tc
, ts
;
462 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_btime
);
463 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_btime
);
465 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
466 "stat_ex.%s differs: "
467 "cookie:'%s' != stat:'%s', "
468 "denying durable reconnect\n",
471 timeval_string(talloc_tos(), &tc
, true),
472 timeval_string(talloc_tos(), &ts
, true)));
476 if (cookie_st
->st_ex_calculated_birthtime
!=
477 fsp_st
->st_ex_calculated_birthtime
)
479 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
480 "stat_ex.%s differs: "
481 "cookie:%llu != stat:%llu, "
482 "denying durable reconnect\n",
484 "st_ex_calculated_birthtime",
485 (unsigned long long)cookie_st
->st_ex_calculated_birthtime
,
486 (unsigned long long)fsp_st
->st_ex_calculated_birthtime
));
490 if (cookie_st
->st_ex_blksize
!= fsp_st
->st_ex_blksize
) {
491 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
492 "stat_ex.%s differs: "
493 "cookie:%llu != stat:%llu, "
494 "denying durable reconnect\n",
497 (unsigned long long)cookie_st
->st_ex_blksize
,
498 (unsigned long long)fsp_st
->st_ex_blksize
));
502 if (cookie_st
->st_ex_blocks
!= fsp_st
->st_ex_blocks
) {
503 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
504 "stat_ex.%s differs: "
505 "cookie:%llu != stat:%llu, "
506 "denying durable reconnect\n",
509 (unsigned long long)cookie_st
->st_ex_blocks
,
510 (unsigned long long)fsp_st
->st_ex_blocks
));
514 if (cookie_st
->st_ex_flags
!= fsp_st
->st_ex_flags
) {
515 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
516 "stat_ex.%s differs: "
517 "cookie:%llu != stat:%llu, "
518 "denying durable reconnect\n",
521 (unsigned long long)cookie_st
->st_ex_flags
,
522 (unsigned long long)fsp_st
->st_ex_flags
));
526 if (cookie_st
->st_ex_mask
!= fsp_st
->st_ex_mask
) {
527 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
528 "stat_ex.%s differs: "
529 "cookie:%llu != stat:%llu, "
530 "denying durable reconnect\n",
533 (unsigned long long)cookie_st
->st_ex_mask
,
534 (unsigned long long)fsp_st
->st_ex_mask
));
541 NTSTATUS
vfs_default_durable_reconnect(struct connection_struct
*conn
,
542 struct smb_request
*smb1req
,
543 struct smbXsrv_open
*op
,
544 const DATA_BLOB old_cookie
,
546 files_struct
**result
,
547 DATA_BLOB
*new_cookie
)
549 struct share_mode_lock
*lck
;
550 struct share_mode_entry
*e
;
551 struct files_struct
*fsp
= NULL
;
556 struct file_id file_id
;
557 struct smb_filename
*smb_fname
= NULL
;
558 enum ndr_err_code ndr_err
;
559 struct vfs_default_durable_cookie cookie
;
560 DATA_BLOB new_cookie_blob
= data_blob_null
;
563 *new_cookie
= data_blob_null
;
565 if (!lp_durable_handles(SNUM(conn
))) {
566 return NT_STATUS_NOT_SUPPORTED
;
570 * the checks for kernel oplocks
571 * and similar things are done
572 * in the vfs_default_durable_cookie()
578 ndr_err
= ndr_pull_struct_blob(&old_cookie
, talloc_tos(), &cookie
,
579 (ndr_pull_flags_fn_t
)ndr_pull_vfs_default_durable_cookie
);
580 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
581 status
= ndr_map_error2ntstatus(ndr_err
);
585 if (strcmp(cookie
.magic
, VFS_DEFAULT_DURABLE_COOKIE_MAGIC
) != 0) {
586 return NT_STATUS_INVALID_PARAMETER
;
589 if (cookie
.version
!= VFS_DEFAULT_DURABLE_COOKIE_VERSION
) {
590 return NT_STATUS_INVALID_PARAMETER
;
593 if (!cookie
.allow_reconnect
) {
594 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
597 if (strcmp(cookie
.servicepath
, conn
->connectpath
) != 0) {
598 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
601 /* Create an smb_filename with stream_name == NULL. */
602 smb_fname
= synthetic_smb_fname(talloc_tos(),
607 if (smb_fname
== NULL
) {
608 return NT_STATUS_NO_MEMORY
;
611 ret
= SMB_VFS_LSTAT(conn
, smb_fname
);
613 status
= map_nt_error_from_unix_common(errno
);
614 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
615 smb_fname_str_dbg(smb_fname
),
620 if (!S_ISREG(smb_fname
->st
.st_ex_mode
)) {
621 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
624 file_id
= vfs_file_id_from_sbuf(conn
, &smb_fname
->st
);
625 if (!file_id_equal(&cookie
.id
, &file_id
)) {
626 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
630 * 1. check entry in locking.tdb
633 lck
= get_existing_share_mode_lock(mem_ctx
, file_id
);
635 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
636 "not obtained from db\n"));
637 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
640 if (lck
->data
->num_share_modes
== 0) {
641 DEBUG(1, ("vfs_default_durable_reconnect: Error: no share-mode "
642 "entry in existing share mode lock\n"));
644 return NT_STATUS_INTERNAL_DB_ERROR
;
647 if (lck
->data
->num_share_modes
> 1) {
649 * It can't be durable if there is more than one handle
652 DEBUG(5, ("vfs_default_durable_reconnect: more than one "
653 "share-mode entry - can not be durable\n"));
655 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
658 e
= &lck
->data
->share_modes
[0];
660 if (!server_id_is_disconnected(&e
->pid
)) {
661 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
662 "reconnect for handle that was not marked "
663 "disconnected (e.g. smbd or cluster node died)\n"));
665 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
668 if (e
->share_file_id
!= op
->global
->open_persistent_id
) {
669 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
670 "share_file_id changed %llu != %llu"
671 "(e.g. another client had opened the file)\n",
672 (unsigned long long)e
->share_file_id
,
673 (unsigned long long)op
->global
->open_persistent_id
));
675 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
678 if ((e
->access_mask
& (FILE_WRITE_DATA
|FILE_APPEND_DATA
)) &&
681 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
682 "share[%s] is not writeable anymore\n",
683 lp_servicename(talloc_tos(), SNUM(conn
))));
685 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
689 * 2. proceed with opening file
692 status
= fsp_new(conn
, conn
, &fsp
);
693 if (!NT_STATUS_IS_OK(status
)) {
694 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
695 "new fsp: %s\n", nt_errstr(status
)));
700 fsp
->fh
->private_options
= e
->private_options
;
701 fsp
->fh
->gen_id
= smbXsrv_open_hash(op
);
702 fsp
->file_id
= file_id
;
703 fsp
->file_pid
= smb1req
->smbpid
;
704 fsp
->vuid
= smb1req
->vuid
;
705 fsp
->open_time
= e
->time
;
706 fsp
->access_mask
= e
->access_mask
;
707 fsp
->share_access
= e
->share_access
;
708 fsp
->can_read
= ((fsp
->access_mask
& (FILE_READ_DATA
)) != 0);
709 fsp
->can_write
= ((fsp
->access_mask
& (FILE_WRITE_DATA
|FILE_APPEND_DATA
)) != 0);
710 fsp
->fnum
= op
->local_id
;
714 * Do we need to store the modified flag in the DB?
716 fsp
->modified
= false;
718 * no durables for directories
720 fsp
->is_directory
= false;
722 * For normal files, can_lock == !is_directory
724 fsp
->can_lock
= true;
726 * We do not support aio write behind for smb2
728 fsp
->aio_write_behind
= false;
729 fsp
->oplock_type
= e
->op_type
;
731 if (fsp
->oplock_type
== LEASE_OPLOCK
) {
732 struct share_mode_lease
*l
= &lck
->data
->leases
[e
->lease_idx
];
733 struct smb2_lease_key key
;
735 key
.data
[0] = l
->lease_key
.data
[0];
736 key
.data
[1] = l
->lease_key
.data
[1];
738 fsp
->lease
= find_fsp_lease(fsp
, &key
, l
);
739 if (fsp
->lease
== NULL
) {
742 return NT_STATUS_NO_MEMORY
;
746 * Ensure the existing client guid matches the
747 * stored one in the share_mode_lease.
749 if (!GUID_equal(fsp_client_guid(fsp
),
753 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
757 fsp
->initial_allocation_size
= cookie
.initial_allocation_size
;
758 fsp
->fh
->position_information
= cookie
.position_information
;
759 fsp
->update_write_time_triggered
= cookie
.update_write_time_triggered
;
760 fsp
->update_write_time_on_close
= cookie
.update_write_time_on_close
;
761 fsp
->write_time_forced
= cookie
.write_time_forced
;
762 fsp
->close_write_time
= cookie
.close_write_time
;
764 status
= fsp_set_smb_fname(fsp
, smb_fname
);
765 if (!NT_STATUS_IS_OK(status
)) {
768 DEBUG(0, ("vfs_default_durable_reconnect: "
769 "fsp_set_smb_fname failed: %s\n",
777 e
->pid
= messaging_server_id(conn
->sconn
->msg_ctx
);
778 e
->op_mid
= smb1req
->mid
;
779 e
->share_file_id
= fsp
->fh
->gen_id
;
781 ok
= brl_reconnect_disconnected(fsp
);
783 status
= NT_STATUS_INTERNAL_ERROR
;
784 DEBUG(1, ("vfs_default_durable_reconnect: "
785 "failed to reopen brlocks: %s\n",
794 * TODO: properly calculate open flags
796 if (fsp
->can_write
&& fsp
->can_read
) {
798 } else if (fsp
->can_write
) {
800 } else if (fsp
->can_read
) {
804 status
= fd_open(conn
, fsp
, flags
, 0 /* mode */);
805 if (!NT_STATUS_IS_OK(status
)) {
807 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
808 "file: %s\n", nt_errstr(status
)));
815 * We now check the stat info stored in the cookie against
816 * the current stat data from the file we just opened.
817 * If any detail differs, we deny the durable reconnect,
818 * because in that case it is very likely that someone
819 * opened the file while the handle was disconnected,
820 * which has to be interpreted as an oplock break.
823 ret
= SMB_VFS_FSTAT(fsp
, &fsp
->fsp_name
->st
);
825 status
= map_nt_error_from_unix_common(errno
);
826 DEBUG(1, ("Unable to fstat stream: %s => %s\n",
827 smb_fname_str_dbg(smb_fname
),
829 ret
= SMB_VFS_CLOSE(fsp
);
831 DEBUG(0, ("vfs_default_durable_reconnect: "
832 "SMB_VFS_CLOSE failed (%s) - leaking file "
833 "descriptor\n", strerror(errno
)));
841 if (!S_ISREG(fsp
->fsp_name
->st
.st_ex_mode
)) {
842 ret
= SMB_VFS_CLOSE(fsp
);
844 DEBUG(0, ("vfs_default_durable_reconnect: "
845 "SMB_VFS_CLOSE failed (%s) - leaking file "
846 "descriptor\n", strerror(errno
)));
851 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
854 file_id
= vfs_file_id_from_sbuf(conn
, &fsp
->fsp_name
->st
);
855 if (!file_id_equal(&cookie
.id
, &file_id
)) {
856 ret
= SMB_VFS_CLOSE(fsp
);
858 DEBUG(0, ("vfs_default_durable_reconnect: "
859 "SMB_VFS_CLOSE failed (%s) - leaking file "
860 "descriptor\n", strerror(errno
)));
865 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
868 ok
= vfs_default_durable_reconnect_check_stat(&cookie
.stat_info
,
872 ret
= SMB_VFS_CLOSE(fsp
);
874 DEBUG(0, ("vfs_default_durable_reconnect: "
875 "SMB_VFS_CLOSE failed (%s) - leaking file "
876 "descriptor\n", strerror(errno
)));
881 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
884 status
= set_file_oplock(fsp
);
885 if (!NT_STATUS_IS_OK(status
)) {
886 DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
887 "after opening file: %s\n", nt_errstr(status
)));
888 ret
= SMB_VFS_CLOSE(fsp
);
890 DEBUG(0, ("vfs_default_durable_reconnect: "
891 "SMB_VFS_CLOSE failed (%s) - leaking file "
892 "descriptor\n", strerror(errno
)));
900 status
= vfs_default_durable_cookie(fsp
, mem_ctx
, &new_cookie_blob
);
901 if (!NT_STATUS_IS_OK(status
)) {
903 DEBUG(1, ("vfs_default_durable_reconnect: "
904 "vfs_default_durable_cookie - %s\n",
911 smb1req
->chain_fsp
= fsp
;
912 smb1req
->smb2req
->compat_chain_fsp
= fsp
;
914 DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
918 * release the sharemode lock: this writes the changes
920 lck
->data
->modified
= true;
924 *new_cookie
= new_cookie_blob
;