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
->fsp_flags
.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
->fsp_flags
.initial_delete_on_close
) {
184 return NT_STATUS_NOT_SUPPORTED
;
186 if (fsp
->fsp_flags
.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_str_dbg(fsp
);
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(),
592 if (smb_fname
== NULL
) {
593 return NT_STATUS_NO_MEMORY
;
596 ret
= SMB_VFS_LSTAT(conn
, smb_fname
);
598 status
= map_nt_error_from_unix_common(errno
);
599 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
600 smb_fname_str_dbg(smb_fname
),
605 if (!S_ISREG(smb_fname
->st
.st_ex_mode
)) {
606 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
609 file_id
= vfs_file_id_from_sbuf(conn
, &smb_fname
->st
);
610 if (!file_id_equal(&cookie
.id
, &file_id
)) {
611 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
615 * 1. check entry in locking.tdb
618 lck
= get_existing_share_mode_lock(mem_ctx
, file_id
);
620 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
621 "not obtained from db\n"));
622 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
625 e
= (struct share_mode_entry
) { .pid
.pid
= 0 };
627 ok
= share_mode_forall_entries(lck
, durable_reconnect_fn
, &e
);
629 DBG_WARNING("share_mode_forall_entries failed\n");
631 return NT_STATUS_INTERNAL_DB_ERROR
;
634 if (e
.pid
.pid
== 0) {
635 DBG_WARNING("Did not find a unique valid share mode entry\n");
637 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
640 if (!server_id_is_disconnected(&e
.pid
)) {
641 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
642 "reconnect for handle that was not marked "
643 "disconnected (e.g. smbd or cluster node died)\n"));
645 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
648 if (e
.share_file_id
!= op
->global
->open_persistent_id
) {
649 DBG_INFO("denying durable "
650 "share_file_id changed %"PRIu64
" != %"PRIu64
" "
651 "(e.g. another client had opened the file)\n",
653 op
->global
->open_persistent_id
);
655 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
658 if ((e
.access_mask
& (FILE_WRITE_DATA
|FILE_APPEND_DATA
)) &&
661 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
662 "share[%s] is not writeable anymore\n",
663 lp_servicename(talloc_tos(), lp_sub
, SNUM(conn
))));
665 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
669 * 2. proceed with opening file
672 status
= fsp_new(conn
, conn
, &fsp
);
673 if (!NT_STATUS_IS_OK(status
)) {
674 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
675 "new fsp: %s\n", nt_errstr(status
)));
680 fsp
->fh
->private_options
= e
.private_options
;
681 fsp
->file_id
= file_id
;
682 fsp
->file_pid
= smb1req
->smbpid
;
683 fsp
->vuid
= smb1req
->vuid
;
684 fsp
->open_time
= e
.time
;
685 fsp
->access_mask
= e
.access_mask
;
686 fsp
->fsp_flags
.can_read
= ((fsp
->access_mask
& FILE_READ_DATA
) != 0);
687 fsp
->fsp_flags
.can_write
= ((fsp
->access_mask
& (FILE_WRITE_DATA
|FILE_APPEND_DATA
)) != 0);
688 fsp
->fnum
= op
->local_id
;
693 * Do we need to store the modified flag in the DB?
695 fsp
->fsp_flags
.modified
= false;
697 * no durables for directories
699 fsp
->fsp_flags
.is_directory
= false;
701 * For normal files, can_lock == !is_directory
703 fsp
->fsp_flags
.can_lock
= true;
705 * We do not support aio write behind for smb2
707 fsp
->fsp_flags
.aio_write_behind
= false;
708 fsp
->oplock_type
= e
.op_type
;
710 if (fsp
->oplock_type
== LEASE_OPLOCK
) {
711 uint32_t current_state
;
712 uint16_t lease_version
, epoch
;
715 * Ensure the existing client guid matches the
716 * stored one in the share_mode_entry.
718 if (!GUID_equal(fsp_client_guid(fsp
),
722 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
725 status
= leases_db_get(
729 ¤t_state
, /* current_state */
731 NULL
, /* breaking_to_requested */
732 NULL
, /* breaking_to_required */
733 &lease_version
, /* lease_version */
735 if (!NT_STATUS_IS_OK(status
)) {
741 fsp
->lease
= find_fsp_lease(
747 if (fsp
->lease
== NULL
) {
750 return NT_STATUS_NO_MEMORY
;
754 fsp
->initial_allocation_size
= cookie
.initial_allocation_size
;
755 fsp
->fh
->position_information
= cookie
.position_information
;
756 fsp
->fsp_flags
.update_write_time_triggered
=
757 cookie
.update_write_time_triggered
;
758 fsp
->fsp_flags
.update_write_time_on_close
=
759 cookie
.update_write_time_on_close
;
760 fsp
->fsp_flags
.write_time_forced
= cookie
.write_time_forced
;
761 fsp
->close_write_time
= nt_time_to_full_timespec(
762 cookie
.close_write_time
);
764 /* TODO: real dirfsp... */
765 fsp
->dirfsp
= fsp
->conn
->cwd_fsp
;
767 status
= fsp_set_smb_fname(fsp
, smb_fname
);
768 if (!NT_STATUS_IS_OK(status
)) {
771 DEBUG(0, ("vfs_default_durable_reconnect: "
772 "fsp_set_smb_fname failed: %s\n",
780 ok
= reset_share_mode_entry(
784 messaging_server_id(conn
->sconn
->msg_ctx
),
788 DBG_DEBUG("Could not set new share_mode_entry values\n");
792 return NT_STATUS_INTERNAL_ERROR
;
795 ok
= brl_reconnect_disconnected(fsp
);
797 status
= NT_STATUS_INTERNAL_ERROR
;
798 DEBUG(1, ("vfs_default_durable_reconnect: "
799 "failed to reopen brlocks: %s\n",
808 * TODO: properly calculate open flags
810 if (fsp
->fsp_flags
.can_write
&& fsp
->fsp_flags
.can_read
) {
812 } else if (fsp
->fsp_flags
.can_write
) {
814 } else if (fsp
->fsp_flags
.can_read
) {
818 status
= fd_openat(fsp
, flags
, 0);
819 if (!NT_STATUS_IS_OK(status
)) {
821 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
822 "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
),
843 ret
= SMB_VFS_CLOSE(fsp
);
845 DEBUG(0, ("vfs_default_durable_reconnect: "
846 "SMB_VFS_CLOSE failed (%s) - leaking file "
847 "descriptor\n", strerror(errno
)));
855 if (!S_ISREG(fsp
->fsp_name
->st
.st_ex_mode
)) {
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 file_id
= vfs_file_id_from_sbuf(conn
, &fsp
->fsp_name
->st
);
869 if (!file_id_equal(&cookie
.id
, &file_id
)) {
870 ret
= SMB_VFS_CLOSE(fsp
);
872 DEBUG(0, ("vfs_default_durable_reconnect: "
873 "SMB_VFS_CLOSE failed (%s) - leaking file "
874 "descriptor\n", strerror(errno
)));
879 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
882 (void)dos_mode(fsp
->conn
, fsp
->fsp_name
);
884 ok
= vfs_default_durable_reconnect_check_stat(&cookie
.stat_info
,
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
)));
897 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
900 status
= set_file_oplock(fsp
);
901 if (!NT_STATUS_IS_OK(status
)) {
902 DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
903 "after opening file: %s\n", nt_errstr(status
)));
904 ret
= SMB_VFS_CLOSE(fsp
);
906 DEBUG(0, ("vfs_default_durable_reconnect: "
907 "SMB_VFS_CLOSE failed (%s) - leaking file "
908 "descriptor\n", strerror(errno
)));
916 status
= vfs_default_durable_cookie(fsp
, mem_ctx
, &new_cookie_blob
);
917 if (!NT_STATUS_IS_OK(status
)) {
919 DEBUG(1, ("vfs_default_durable_reconnect: "
920 "vfs_default_durable_cookie - %s\n",
927 smb1req
->chain_fsp
= fsp
;
928 smb1req
->smb2req
->compat_chain_fsp
= fsp
;
930 DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
934 * release the sharemode lock: this writes the changes
936 lck
->data
->modified
= true;
940 *new_cookie
= new_cookie_blob
;