2 Unix SMB/CIFS implementation.
3 Durable Handle default VFS implementation
5 Copyright (C) Stefan Metzmacher 2012
6 Copyright (C) Michael Adam 2012
7 Copyright (C) Volker Lendecke 2012
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/filesys.h"
25 #include "lib/util/server_id.h"
26 #include "locking/share_mode_lock.h"
27 #include "smbd/smbd.h"
28 #include "smbd/globals.h"
29 #include "libcli/security/security.h"
31 #include "librpc/gen_ndr/ndr_open_files.h"
33 #include "fake_file.h"
34 #include "locking/leases_db.h"
36 NTSTATUS
vfs_default_durable_cookie(struct files_struct
*fsp
,
38 DATA_BLOB
*cookie_blob
)
40 struct connection_struct
*conn
= fsp
->conn
;
41 enum ndr_err_code ndr_err
;
42 struct vfs_default_durable_cookie cookie
;
44 if (!lp_durable_handles(SNUM(conn
))) {
45 return NT_STATUS_NOT_SUPPORTED
;
48 if (lp_kernel_share_modes(SNUM(conn
))) {
50 * We do not support durable handles
51 * if file system sharemodes are used
53 return NT_STATUS_NOT_SUPPORTED
;
56 if (lp_kernel_oplocks(SNUM(conn
))) {
58 * We do not support durable handles
59 * if kernel oplocks are used
61 return NT_STATUS_NOT_SUPPORTED
;
64 if ((fsp
->current_lock_count
> 0) &&
65 lp_posix_locking(fsp
->conn
->params
))
68 * We do not support durable handles
69 * if the handle has posix locks.
71 return NT_STATUS_NOT_SUPPORTED
;
74 if (fsp
->fsp_flags
.is_directory
) {
75 return NT_STATUS_NOT_SUPPORTED
;
78 if (fsp_is_alternate_stream(fsp
)) {
80 * We do not support durable handles
83 return NT_STATUS_NOT_SUPPORTED
;
86 if (is_fake_file(fsp
->fsp_name
)) {
88 * We do not support durable handles
91 return NT_STATUS_NOT_SUPPORTED
;
95 cookie
.allow_reconnect
= false;
96 cookie
.id
= fsp
->file_id
;
97 cookie
.servicepath
= conn
->connectpath
;
98 cookie
.base_name
= fsp
->fsp_name
->base_name
;
99 cookie
.initial_allocation_size
= fsp
->initial_allocation_size
;
100 cookie
.position_information
= fh_get_position_information(fsp
->fh
);
101 cookie
.update_write_time_triggered
=
102 fsp
->fsp_flags
.update_write_time_triggered
;
103 cookie
.update_write_time_on_close
=
104 fsp
->fsp_flags
.update_write_time_on_close
;
105 cookie
.write_time_forced
= fsp
->fsp_flags
.write_time_forced
;
106 cookie
.close_write_time
= full_timespec_to_nt_time(
107 &fsp
->close_write_time
);
109 cookie
.stat_info
.st_ex_dev
= fsp
->fsp_name
->st
.st_ex_dev
;
110 cookie
.stat_info
.st_ex_ino
= fsp
->fsp_name
->st
.st_ex_ino
;
111 cookie
.stat_info
.st_ex_mode
= fsp
->fsp_name
->st
.st_ex_mode
;
112 cookie
.stat_info
.st_ex_nlink
= fsp
->fsp_name
->st
.st_ex_nlink
;
113 cookie
.stat_info
.st_ex_uid
= fsp
->fsp_name
->st
.st_ex_uid
;
114 cookie
.stat_info
.st_ex_gid
= fsp
->fsp_name
->st
.st_ex_gid
;
115 cookie
.stat_info
.st_ex_rdev
= fsp
->fsp_name
->st
.st_ex_rdev
;
116 cookie
.stat_info
.st_ex_size
= fsp
->fsp_name
->st
.st_ex_size
;
117 cookie
.stat_info
.st_ex_atime
= fsp
->fsp_name
->st
.st_ex_atime
;
118 cookie
.stat_info
.st_ex_mtime
= fsp
->fsp_name
->st
.st_ex_mtime
;
119 cookie
.stat_info
.st_ex_ctime
= fsp
->fsp_name
->st
.st_ex_ctime
;
120 cookie
.stat_info
.st_ex_btime
= fsp
->fsp_name
->st
.st_ex_btime
;
121 cookie
.stat_info
.st_ex_iflags
= fsp
->fsp_name
->st
.st_ex_iflags
;
122 cookie
.stat_info
.st_ex_blksize
= fsp
->fsp_name
->st
.st_ex_blksize
;
123 cookie
.stat_info
.st_ex_blocks
= fsp
->fsp_name
->st
.st_ex_blocks
;
124 cookie
.stat_info
.st_ex_flags
= fsp
->fsp_name
->st
.st_ex_flags
;
126 ndr_err
= ndr_push_struct_blob(cookie_blob
, mem_ctx
, &cookie
,
127 (ndr_push_flags_fn_t
)ndr_push_vfs_default_durable_cookie
);
128 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
129 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
136 NTSTATUS
vfs_default_durable_disconnect(struct files_struct
*fsp
,
137 const DATA_BLOB old_cookie
,
139 DATA_BLOB
*new_cookie
)
141 struct connection_struct
*conn
= fsp
->conn
;
143 enum ndr_err_code ndr_err
;
144 struct vfs_default_durable_cookie cookie
;
145 DATA_BLOB new_cookie_blob
= data_blob_null
;
146 struct share_mode_lock
*lck
;
149 *new_cookie
= data_blob_null
;
153 ndr_err
= ndr_pull_struct_blob(&old_cookie
, talloc_tos(), &cookie
,
154 (ndr_pull_flags_fn_t
)ndr_pull_vfs_default_durable_cookie
);
155 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
156 status
= ndr_map_error2ntstatus(ndr_err
);
160 if (strcmp(cookie
.magic
, VFS_DEFAULT_DURABLE_COOKIE_MAGIC
) != 0) {
161 return NT_STATUS_INVALID_PARAMETER
;
164 if (cookie
.version
!= VFS_DEFAULT_DURABLE_COOKIE_VERSION
) {
165 return NT_STATUS_INVALID_PARAMETER
;
168 if (!file_id_equal(&fsp
->file_id
, &cookie
.id
)) {
169 return NT_STATUS_INVALID_PARAMETER
;
172 if ((fsp_lease_type(fsp
) & SMB2_LEASE_HANDLE
) == 0) {
173 return NT_STATUS_NOT_SUPPORTED
;
176 if (fsp
->current_lock_count
!= 0 &&
177 (fsp_lease_type(fsp
) & SMB2_LEASE_WRITE
) == 0)
179 return NT_STATUS_NOT_SUPPORTED
;
183 * For now let it be simple and do not keep
184 * delete on close files durable open
186 if (fsp
->fsp_flags
.initial_delete_on_close
) {
187 return NT_STATUS_NOT_SUPPORTED
;
189 if (fsp
->fsp_flags
.delete_on_close
) {
190 return NT_STATUS_NOT_SUPPORTED
;
193 if (!VALID_STAT(fsp
->fsp_name
->st
)) {
194 return NT_STATUS_NOT_SUPPORTED
;
197 if (!S_ISREG(fsp
->fsp_name
->st
.st_ex_mode
)) {
198 return NT_STATUS_NOT_SUPPORTED
;
201 /* Ensure any pending write time updates are done. */
202 if (fsp
->update_write_time_event
) {
203 fsp_flush_write_time_update(fsp
);
207 * The above checks are done in mark_share_mode_disconnected() too
208 * but we want to avoid getting the lock if possible
210 lck
= get_existing_share_mode_lock(talloc_tos(), fsp
->file_id
);
212 struct smb_file_time ft
;
214 init_smb_file_time(&ft
);
216 if (fsp
->fsp_flags
.write_time_forced
) {
217 NTTIME mtime
= share_mode_changed_write_time(lck
);
218 ft
.mtime
= nt_time_to_full_timespec(mtime
);
219 } else if (fsp
->fsp_flags
.update_write_time_on_close
) {
220 if (is_omit_timespec(&fsp
->close_write_time
)) {
221 ft
.mtime
= timespec_current();
223 ft
.mtime
= fsp
->close_write_time
;
227 if (!is_omit_timespec(&ft
.mtime
)) {
228 round_timespec(conn
->ts_res
, &ft
.mtime
);
229 file_ntimes(conn
, fsp
, &ft
);
232 ok
= mark_share_mode_disconnected(lck
, fsp
);
238 ok
= brl_mark_disconnected(fsp
);
244 return NT_STATUS_NOT_SUPPORTED
;
248 status
= vfs_stat_fsp(fsp
);
249 if (!NT_STATUS_IS_OK(status
)) {
254 cookie
.allow_reconnect
= true;
255 cookie
.id
= fsp
->file_id
;
256 cookie
.servicepath
= conn
->connectpath
;
257 cookie
.base_name
= fsp_str_dbg(fsp
);
258 cookie
.initial_allocation_size
= fsp
->initial_allocation_size
;
259 cookie
.position_information
= fh_get_position_information(fsp
->fh
);
260 cookie
.update_write_time_triggered
=
261 fsp
->fsp_flags
.update_write_time_triggered
;
262 cookie
.update_write_time_on_close
=
263 fsp
->fsp_flags
.update_write_time_on_close
;
264 cookie
.write_time_forced
= fsp
->fsp_flags
.write_time_forced
;
265 cookie
.close_write_time
= full_timespec_to_nt_time(
266 &fsp
->close_write_time
);
268 cookie
.stat_info
.st_ex_dev
= fsp
->fsp_name
->st
.st_ex_dev
;
269 cookie
.stat_info
.st_ex_ino
= fsp
->fsp_name
->st
.st_ex_ino
;
270 cookie
.stat_info
.st_ex_mode
= fsp
->fsp_name
->st
.st_ex_mode
;
271 cookie
.stat_info
.st_ex_nlink
= fsp
->fsp_name
->st
.st_ex_nlink
;
272 cookie
.stat_info
.st_ex_uid
= fsp
->fsp_name
->st
.st_ex_uid
;
273 cookie
.stat_info
.st_ex_gid
= fsp
->fsp_name
->st
.st_ex_gid
;
274 cookie
.stat_info
.st_ex_rdev
= fsp
->fsp_name
->st
.st_ex_rdev
;
275 cookie
.stat_info
.st_ex_size
= fsp
->fsp_name
->st
.st_ex_size
;
276 cookie
.stat_info
.st_ex_atime
= fsp
->fsp_name
->st
.st_ex_atime
;
277 cookie
.stat_info
.st_ex_mtime
= fsp
->fsp_name
->st
.st_ex_mtime
;
278 cookie
.stat_info
.st_ex_ctime
= fsp
->fsp_name
->st
.st_ex_ctime
;
279 cookie
.stat_info
.st_ex_btime
= fsp
->fsp_name
->st
.st_ex_btime
;
280 cookie
.stat_info
.st_ex_iflags
= fsp
->fsp_name
->st
.st_ex_iflags
;
281 cookie
.stat_info
.st_ex_blksize
= fsp
->fsp_name
->st
.st_ex_blksize
;
282 cookie
.stat_info
.st_ex_blocks
= fsp
->fsp_name
->st
.st_ex_blocks
;
283 cookie
.stat_info
.st_ex_flags
= fsp
->fsp_name
->st
.st_ex_flags
;
285 ndr_err
= ndr_push_struct_blob(&new_cookie_blob
, mem_ctx
, &cookie
,
286 (ndr_push_flags_fn_t
)ndr_push_vfs_default_durable_cookie
);
287 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
288 status
= ndr_map_error2ntstatus(ndr_err
);
292 status
= fd_close(fsp
);
293 if (!NT_STATUS_IS_OK(status
)) {
294 data_blob_free(&new_cookie_blob
);
298 *new_cookie
= new_cookie_blob
;
304 * Check whether a cookie-stored struct info is the same
305 * as a given SMB_STRUCT_STAT, as coming with the fsp.
307 static bool vfs_default_durable_reconnect_check_stat(
308 struct vfs_default_durable_stat
*cookie_st
,
309 SMB_STRUCT_STAT
*fsp_st
,
314 if (cookie_st
->st_ex_mode
!= fsp_st
->st_ex_mode
) {
315 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
316 "stat_ex.%s differs: "
317 "cookie:%llu != stat:%llu, "
318 "denying durable reconnect\n",
321 (unsigned long long)cookie_st
->st_ex_mode
,
322 (unsigned long long)fsp_st
->st_ex_mode
));
326 if (cookie_st
->st_ex_nlink
!= fsp_st
->st_ex_nlink
) {
327 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
328 "stat_ex.%s differs: "
329 "cookie:%llu != stat:%llu, "
330 "denying durable reconnect\n",
333 (unsigned long long)cookie_st
->st_ex_nlink
,
334 (unsigned long long)fsp_st
->st_ex_nlink
));
338 if (cookie_st
->st_ex_uid
!= fsp_st
->st_ex_uid
) {
339 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
340 "stat_ex.%s differs: "
341 "cookie:%llu != stat:%llu, "
342 "denying durable reconnect\n",
345 (unsigned long long)cookie_st
->st_ex_uid
,
346 (unsigned long long)fsp_st
->st_ex_uid
));
350 if (cookie_st
->st_ex_gid
!= fsp_st
->st_ex_gid
) {
351 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
352 "stat_ex.%s differs: "
353 "cookie:%llu != stat:%llu, "
354 "denying durable reconnect\n",
357 (unsigned long long)cookie_st
->st_ex_gid
,
358 (unsigned long long)fsp_st
->st_ex_gid
));
362 if (cookie_st
->st_ex_rdev
!= fsp_st
->st_ex_rdev
) {
363 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
364 "stat_ex.%s differs: "
365 "cookie:%llu != stat:%llu, "
366 "denying durable reconnect\n",
369 (unsigned long long)cookie_st
->st_ex_rdev
,
370 (unsigned long long)fsp_st
->st_ex_rdev
));
374 if (cookie_st
->st_ex_size
!= fsp_st
->st_ex_size
) {
375 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
376 "stat_ex.%s differs: "
377 "cookie:%llu != stat:%llu, "
378 "denying durable reconnect\n",
381 (unsigned long long)cookie_st
->st_ex_size
,
382 (unsigned long long)fsp_st
->st_ex_size
));
386 ret
= timespec_compare(&cookie_st
->st_ex_atime
,
387 &fsp_st
->st_ex_atime
);
389 struct timeval tc
, ts
;
390 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_atime
);
391 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_atime
);
393 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
394 "stat_ex.%s differs: "
395 "cookie:'%s' != stat:'%s', "
396 "denying durable reconnect\n",
399 timeval_string(talloc_tos(), &tc
, true),
400 timeval_string(talloc_tos(), &ts
, true)));
404 ret
= timespec_compare(&cookie_st
->st_ex_mtime
,
405 &fsp_st
->st_ex_mtime
);
407 struct timeval tc
, ts
;
408 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_mtime
);
409 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_mtime
);
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_ctime
,
423 &fsp_st
->st_ex_ctime
);
425 struct timeval tc
, ts
;
426 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_ctime
);
427 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_ctime
);
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_btime
,
441 &fsp_st
->st_ex_btime
);
443 struct timeval tc
, ts
;
444 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_btime
);
445 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_btime
);
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 if (cookie_st
->st_ex_iflags
!= fsp_st
->st_ex_iflags
) {
459 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
460 "stat_ex.%s differs: "
461 "cookie:%llu != stat:%llu, "
462 "denying durable reconnect\n",
464 "st_ex_calculated_birthtime",
465 (unsigned long long)cookie_st
->st_ex_iflags
,
466 (unsigned long long)fsp_st
->st_ex_iflags
));
470 if (cookie_st
->st_ex_blksize
!= fsp_st
->st_ex_blksize
) {
471 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
472 "stat_ex.%s differs: "
473 "cookie:%llu != stat:%llu, "
474 "denying durable reconnect\n",
477 (unsigned long long)cookie_st
->st_ex_blksize
,
478 (unsigned long long)fsp_st
->st_ex_blksize
));
482 if (cookie_st
->st_ex_blocks
!= fsp_st
->st_ex_blocks
) {
483 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
484 "stat_ex.%s differs: "
485 "cookie:%llu != stat:%llu, "
486 "denying durable reconnect\n",
489 (unsigned long long)cookie_st
->st_ex_blocks
,
490 (unsigned long long)fsp_st
->st_ex_blocks
));
494 if (cookie_st
->st_ex_flags
!= fsp_st
->st_ex_flags
) {
495 DBG_WARNING(" (%s): "
496 "stat_ex.%s differs: "
497 "cookie:%"PRIu32
" != stat:%"PRIu32
", "
498 "denying durable reconnect\n",
501 cookie_st
->st_ex_flags
,
502 fsp_st
->st_ex_flags
);
509 struct durable_reconnect_state
{
510 struct smbXsrv_open
*op
;
511 struct share_mode_entry
*e
;
514 static bool durable_reconnect_fn(
515 struct share_mode_entry
*e
,
519 struct durable_reconnect_state
*state
= private_data
;
520 uint64_t id
= state
->op
->global
->open_persistent_id
;
522 if (e
->share_file_id
!= id
) {
523 return false; /* Look at potential other entries */
526 if (!server_id_is_disconnected(&e
->pid
)) {
527 return false; /* Look at potential other entries */
530 if (state
->e
->share_file_id
== id
) {
531 DBG_INFO("Found more than one entry, invalidating previous\n");
532 *state
->e
= (struct share_mode_entry
) { .pid
= { .pid
= 0, }};
533 return true; /* end the loop through share mode entries */
536 return false; /* Look at potential other entries */
539 NTSTATUS
vfs_default_durable_reconnect(struct connection_struct
*conn
,
540 struct smb_request
*smb1req
,
541 struct smbXsrv_open
*op
,
542 const DATA_BLOB old_cookie
,
544 files_struct
**result
,
545 DATA_BLOB
*new_cookie
)
547 const struct loadparm_substitution
*lp_sub
=
548 loadparm_s3_global_substitution();
549 struct share_mode_lock
*lck
;
550 struct share_mode_entry e
= { .pid
= { .pid
= 0, }};
551 struct durable_reconnect_state rstate
= { .op
= op
, .e
= &e
, };
552 struct files_struct
*fsp
= NULL
;
556 struct vfs_open_how how
= { .flags
= 0, };
557 struct file_id file_id
;
558 struct smb_filename
*smb_fname
= NULL
;
559 enum ndr_err_code ndr_err
;
560 struct vfs_default_durable_cookie cookie
;
561 DATA_BLOB new_cookie_blob
= data_blob_null
;
562 bool have_share_mode_entry
= false;
565 *new_cookie
= data_blob_null
;
567 if (!lp_durable_handles(SNUM(conn
))) {
568 return NT_STATUS_NOT_SUPPORTED
;
572 * the checks for kernel oplocks
573 * and similar things are done
574 * in the vfs_default_durable_cookie()
578 ndr_err
= ndr_pull_struct_blob_all(
582 (ndr_pull_flags_fn_t
)ndr_pull_vfs_default_durable_cookie
);
583 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
584 status
= ndr_map_error2ntstatus(ndr_err
);
588 if (strcmp(cookie
.magic
, VFS_DEFAULT_DURABLE_COOKIE_MAGIC
) != 0) {
589 return NT_STATUS_INVALID_PARAMETER
;
592 if (cookie
.version
!= VFS_DEFAULT_DURABLE_COOKIE_VERSION
) {
593 return NT_STATUS_INVALID_PARAMETER
;
596 if (!cookie
.allow_reconnect
) {
597 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
600 if (strcmp(cookie
.servicepath
, conn
->connectpath
) != 0) {
601 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
604 /* Create an smb_filename with stream_name == NULL. */
605 smb_fname
= synthetic_smb_fname(talloc_tos(),
611 if (smb_fname
== NULL
) {
612 return NT_STATUS_NO_MEMORY
;
615 ret
= SMB_VFS_LSTAT(conn
, smb_fname
);
617 status
= map_nt_error_from_unix_common(errno
);
618 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
619 smb_fname_str_dbg(smb_fname
),
624 if (!S_ISREG(smb_fname
->st
.st_ex_mode
)) {
625 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
628 file_id
= vfs_file_id_from_sbuf(conn
, &smb_fname
->st
);
629 if (!file_id_equal(&cookie
.id
, &file_id
)) {
630 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
634 * 1. check entry in locking.tdb
637 lck
= get_existing_share_mode_lock(mem_ctx
, file_id
);
639 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
640 "not obtained from db\n"));
641 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
644 ok
= share_mode_forall_entries(lck
, durable_reconnect_fn
, &rstate
);
646 DBG_WARNING("share_mode_forall_entries failed\n");
647 status
= NT_STATUS_INTERNAL_DB_ERROR
;
651 if (e
.pid
.pid
== 0) {
652 DBG_WARNING("Did not find a unique valid share mode entry\n");
653 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
657 if (!server_id_is_disconnected(&e
.pid
)) {
658 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
659 "reconnect for handle that was not marked "
660 "disconnected (e.g. smbd or cluster node died)\n"));
661 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
665 if (e
.share_file_id
!= op
->global
->open_persistent_id
) {
666 DBG_INFO("denying durable "
667 "share_file_id changed %"PRIu64
" != %"PRIu64
" "
668 "(e.g. another client had opened the file)\n",
670 op
->global
->open_persistent_id
);
671 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
675 if ((e
.access_mask
& (FILE_WRITE_DATA
|FILE_APPEND_DATA
)) &&
678 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
679 "share[%s] is not writeable anymore\n",
680 lp_servicename(talloc_tos(), lp_sub
, SNUM(conn
))));
681 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
686 * 2. proceed with opening file
689 status
= fsp_new(conn
, conn
, &fsp
);
690 if (!NT_STATUS_IS_OK(status
)) {
691 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
692 "new fsp: %s\n", nt_errstr(status
)));
696 fh_set_private_options(fsp
->fh
, e
.private_options
);
697 fsp
->file_id
= file_id
;
698 fsp
->file_pid
= smb1req
->smbpid
;
699 fsp
->vuid
= smb1req
->vuid
;
700 fsp
->open_time
= e
.time
;
701 fsp
->access_mask
= e
.access_mask
;
702 fsp
->fsp_flags
.can_read
= ((fsp
->access_mask
& FILE_READ_DATA
) != 0);
703 fsp
->fsp_flags
.can_write
= ((fsp
->access_mask
& (FILE_WRITE_DATA
|FILE_APPEND_DATA
)) != 0);
704 fsp
->fnum
= op
->local_id
;
709 * Do we need to store the modified flag in the DB?
711 fsp
->fsp_flags
.modified
= false;
713 * no durables for directories
715 fsp
->fsp_flags
.is_directory
= false;
717 * For normal files, can_lock == !is_directory
719 fsp
->fsp_flags
.can_lock
= true;
721 * We do not support aio write behind for smb2
723 fsp
->fsp_flags
.aio_write_behind
= false;
724 fsp
->oplock_type
= e
.op_type
;
726 if (fsp
->oplock_type
== LEASE_OPLOCK
) {
727 uint32_t current_state
;
728 uint16_t lease_version
, epoch
;
731 * Ensure the existing client guid matches the
732 * stored one in the share_mode_entry.
734 if (!GUID_equal(fsp_client_guid(fsp
),
736 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
740 status
= leases_db_get(
744 ¤t_state
, /* current_state */
746 NULL
, /* breaking_to_requested */
747 NULL
, /* breaking_to_required */
748 &lease_version
, /* lease_version */
750 if (!NT_STATUS_IS_OK(status
)) {
754 fsp
->lease
= find_fsp_lease(
760 if (fsp
->lease
== NULL
) {
761 status
= NT_STATUS_NO_MEMORY
;
766 fsp
->initial_allocation_size
= cookie
.initial_allocation_size
;
767 fh_set_position_information(fsp
->fh
, cookie
.position_information
);
768 fsp
->fsp_flags
.update_write_time_triggered
=
769 cookie
.update_write_time_triggered
;
770 fsp
->fsp_flags
.update_write_time_on_close
=
771 cookie
.update_write_time_on_close
;
772 fsp
->fsp_flags
.write_time_forced
= cookie
.write_time_forced
;
773 fsp
->close_write_time
= nt_time_to_full_timespec(
774 cookie
.close_write_time
);
776 status
= fsp_set_smb_fname(fsp
, smb_fname
);
777 if (!NT_STATUS_IS_OK(status
)) {
778 DEBUG(0, ("vfs_default_durable_reconnect: "
779 "fsp_set_smb_fname failed: %s\n",
787 ok
= reset_share_mode_entry(
791 messaging_server_id(conn
->sconn
->msg_ctx
),
793 fh_get_gen_id(fsp
->fh
));
795 DBG_DEBUG("Could not set new share_mode_entry values\n");
796 status
= NT_STATUS_INTERNAL_ERROR
;
799 have_share_mode_entry
= true;
801 ok
= brl_reconnect_disconnected(fsp
);
803 status
= NT_STATUS_INTERNAL_ERROR
;
804 DEBUG(1, ("vfs_default_durable_reconnect: "
805 "failed to reopen brlocks: %s\n",
811 * TODO: properly calculate open flags
813 if (fsp
->fsp_flags
.can_write
&& fsp
->fsp_flags
.can_read
) {
815 } else if (fsp
->fsp_flags
.can_write
) {
816 how
.flags
= O_WRONLY
;
817 } else if (fsp
->fsp_flags
.can_read
) {
818 how
.flags
= O_RDONLY
;
821 status
= fd_openat(conn
->cwd_fsp
, fsp
->fsp_name
, fsp
, &how
);
822 if (!NT_STATUS_IS_OK(status
)) {
823 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
824 "file: %s\n", nt_errstr(status
)));
829 * We now check the stat info stored in the cookie against
830 * the current stat data from the file we just opened.
831 * If any detail differs, we deny the durable reconnect,
832 * because in that case it is very likely that someone
833 * opened the file while the handle was disconnected,
834 * which has to be interpreted as an oplock break.
837 ret
= SMB_VFS_FSTAT(fsp
, &fsp
->fsp_name
->st
);
839 status
= map_nt_error_from_unix_common(errno
);
840 DEBUG(1, ("Unable to fstat stream: %s => %s\n",
841 smb_fname_str_dbg(smb_fname
),
846 if (!S_ISREG(fsp
->fsp_name
->st
.st_ex_mode
)) {
847 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
851 file_id
= vfs_file_id_from_sbuf(conn
, &fsp
->fsp_name
->st
);
852 if (!file_id_equal(&cookie
.id
, &file_id
)) {
853 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
857 (void)fdos_mode(fsp
);
859 ok
= vfs_default_durable_reconnect_check_stat(&cookie
.stat_info
,
863 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
867 status
= set_file_oplock(fsp
);
868 if (!NT_STATUS_IS_OK(status
)) {
872 status
= vfs_default_durable_cookie(fsp
, mem_ctx
, &new_cookie_blob
);
873 if (!NT_STATUS_IS_OK(status
)) {
874 DEBUG(1, ("vfs_default_durable_reconnect: "
875 "vfs_default_durable_cookie - %s\n",
880 smb1req
->chain_fsp
= fsp
;
881 smb1req
->smb2req
->compat_chain_fsp
= fsp
;
883 DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
888 fsp
->fsp_flags
.is_fsa
= true;
891 *new_cookie
= new_cookie_blob
;
896 if (fsp
!= NULL
&& have_share_mode_entry
) {
898 * Something is screwed up, delete the sharemode entry.
900 del_share_mode(lck
, fsp
);
902 if (fsp
!= NULL
&& fsp_get_pathref_fd(fsp
) != -1) {
903 NTSTATUS close_status
;
904 close_status
= fd_close(fsp
);
905 if (!NT_STATUS_IS_OK(close_status
)) {
906 DBG_ERR("fd_close failed (%s), leaking fd\n",
907 nt_errstr(close_status
));
914 file_free(smb1req
, fsp
);