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 "smbd/smbd.h"
26 #include "smbd/globals.h"
27 #include "libcli/security/security.h"
29 #include "librpc/gen_ndr/ndr_open_files.h"
31 #include "fake_file.h"
33 NTSTATUS
vfs_default_durable_cookie(struct files_struct
*fsp
,
35 DATA_BLOB
*cookie_blob
)
37 struct connection_struct
*conn
= fsp
->conn
;
38 enum ndr_err_code ndr_err
;
39 struct vfs_default_durable_cookie cookie
;
41 if (!lp_durable_handles(SNUM(conn
))) {
42 return NT_STATUS_NOT_SUPPORTED
;
45 if (lp_kernel_share_modes(SNUM(conn
))) {
47 * We do not support durable handles
48 * if kernel share modes (flocks) are used
50 return NT_STATUS_NOT_SUPPORTED
;
53 if (lp_kernel_oplocks(SNUM(conn
))) {
55 * We do not support durable handles
56 * if kernel oplocks are used
58 return NT_STATUS_NOT_SUPPORTED
;
61 if ((fsp
->current_lock_count
> 0) &&
62 lp_posix_locking(fsp
->conn
->params
))
65 * We do not support durable handles
66 * if the handle has posix locks.
68 return NT_STATUS_NOT_SUPPORTED
;
71 if (fsp
->is_directory
) {
72 return NT_STATUS_NOT_SUPPORTED
;
75 if (fsp
->fh
->fd
== -1) {
76 return NT_STATUS_NOT_SUPPORTED
;
79 if (is_ntfs_stream_smb_fname(fsp
->fsp_name
)) {
81 * We do not support durable handles
84 return NT_STATUS_NOT_SUPPORTED
;
87 if (is_fake_file(fsp
->fsp_name
)) {
89 * We do not support durable handles
92 return NT_STATUS_NOT_SUPPORTED
;
96 cookie
.allow_reconnect
= false;
97 cookie
.id
= fsp
->file_id
;
98 cookie
.servicepath
= conn
->connectpath
;
99 cookie
.base_name
= fsp
->fsp_name
->base_name
;
100 cookie
.initial_allocation_size
= fsp
->initial_allocation_size
;
101 cookie
.position_information
= fsp
->fh
->position_information
;
102 cookie
.update_write_time_triggered
= fsp
->update_write_time_triggered
;
103 cookie
.update_write_time_on_close
= fsp
->update_write_time_on_close
;
104 cookie
.write_time_forced
= fsp
->write_time_forced
;
105 cookie
.close_write_time
= fsp
->close_write_time
;
107 cookie
.stat_info
.st_ex_dev
= fsp
->fsp_name
->st
.st_ex_dev
;
108 cookie
.stat_info
.st_ex_ino
= fsp
->fsp_name
->st
.st_ex_ino
;
109 cookie
.stat_info
.st_ex_mode
= fsp
->fsp_name
->st
.st_ex_mode
;
110 cookie
.stat_info
.st_ex_nlink
= fsp
->fsp_name
->st
.st_ex_nlink
;
111 cookie
.stat_info
.st_ex_uid
= fsp
->fsp_name
->st
.st_ex_uid
;
112 cookie
.stat_info
.st_ex_gid
= fsp
->fsp_name
->st
.st_ex_gid
;
113 cookie
.stat_info
.st_ex_rdev
= fsp
->fsp_name
->st
.st_ex_rdev
;
114 cookie
.stat_info
.st_ex_size
= fsp
->fsp_name
->st
.st_ex_size
;
115 cookie
.stat_info
.st_ex_atime
= fsp
->fsp_name
->st
.st_ex_atime
;
116 cookie
.stat_info
.st_ex_mtime
= fsp
->fsp_name
->st
.st_ex_mtime
;
117 cookie
.stat_info
.st_ex_ctime
= fsp
->fsp_name
->st
.st_ex_ctime
;
118 cookie
.stat_info
.st_ex_btime
= fsp
->fsp_name
->st
.st_ex_btime
;
119 cookie
.stat_info
.st_ex_calculated_birthtime
= fsp
->fsp_name
->st
.st_ex_calculated_birthtime
;
120 cookie
.stat_info
.st_ex_blksize
= fsp
->fsp_name
->st
.st_ex_blksize
;
121 cookie
.stat_info
.st_ex_blocks
= fsp
->fsp_name
->st
.st_ex_blocks
;
122 cookie
.stat_info
.st_ex_flags
= fsp
->fsp_name
->st
.st_ex_flags
;
123 cookie
.stat_info
.st_ex_mask
= fsp
->fsp_name
->st
.st_ex_mask
;
124 cookie
.stat_info
.vfs_private
= fsp
->fsp_name
->st
.vfs_private
;
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 (!BATCH_OPLOCK_TYPE(fsp
->oplock_type
)) {
173 return NT_STATUS_NOT_SUPPORTED
;
176 if (fsp
->num_pending_break_messages
> 0) {
177 return NT_STATUS_NOT_SUPPORTED
;
181 * For now let it be simple and do not keep
182 * delete on close files durable open
184 if (fsp
->initial_delete_on_close
) {
185 return NT_STATUS_NOT_SUPPORTED
;
187 if (fsp
->delete_on_close
) {
188 return NT_STATUS_NOT_SUPPORTED
;
191 if (!VALID_STAT(fsp
->fsp_name
->st
)) {
192 return NT_STATUS_NOT_SUPPORTED
;
195 if (!S_ISREG(fsp
->fsp_name
->st
.st_ex_mode
)) {
196 return NT_STATUS_NOT_SUPPORTED
;
199 /* Ensure any pending write time updates are done. */
200 if (fsp
->update_write_time_event
) {
201 update_write_time_handler(fsp
->conn
->sconn
->ev_ctx
,
202 fsp
->update_write_time_event
,
208 * The above checks are done in mark_share_mode_disconnected() too
209 * but we want to avoid getting the lock if possible
211 lck
= get_existing_share_mode_lock(talloc_tos(), fsp
->file_id
);
213 struct smb_file_time ft
;
217 if (fsp
->write_time_forced
) {
218 ft
.mtime
= lck
->data
->changed_write_time
;
219 } else if (fsp
->update_write_time_on_close
) {
220 if (null_timespec(fsp
->close_write_time
)) {
221 ft
.mtime
= timespec_current();
223 ft
.mtime
= fsp
->close_write_time
;
227 if (!null_timespec(ft
.mtime
)) {
228 round_timespec(conn
->ts_res
, &ft
.mtime
);
229 file_ntimes(conn
, fsp
->fsp_name
, &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
->fsp_name
->base_name
;
258 cookie
.initial_allocation_size
= fsp
->initial_allocation_size
;
259 cookie
.position_information
= fsp
->fh
->position_information
;
260 cookie
.update_write_time_triggered
= fsp
->update_write_time_triggered
;
261 cookie
.update_write_time_on_close
= fsp
->update_write_time_on_close
;
262 cookie
.write_time_forced
= fsp
->write_time_forced
;
263 cookie
.close_write_time
= 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_calculated_birthtime
= fsp
->fsp_name
->st
.st_ex_calculated_birthtime
;
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
;
281 cookie
.stat_info
.st_ex_mask
= fsp
->fsp_name
->st
.st_ex_mask
;
282 cookie
.stat_info
.vfs_private
= fsp
->fsp_name
->st
.vfs_private
;
284 ndr_err
= ndr_push_struct_blob(&new_cookie_blob
, mem_ctx
, &cookie
,
285 (ndr_push_flags_fn_t
)ndr_push_vfs_default_durable_cookie
);
286 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
287 status
= ndr_map_error2ntstatus(ndr_err
);
291 status
= fd_close(fsp
);
292 if (!NT_STATUS_IS_OK(status
)) {
293 data_blob_free(&new_cookie_blob
);
297 *new_cookie
= new_cookie_blob
;
303 * Check whether a cookie-stored struct info is the same
304 * as a given SMB_STRUCT_STAT, as coming with the fsp.
306 static bool vfs_default_durable_reconnect_check_stat(
307 struct vfs_default_durable_stat
*cookie_st
,
308 SMB_STRUCT_STAT
*fsp_st
,
313 if (cookie_st
->st_ex_dev
!= fsp_st
->st_ex_dev
) {
314 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
315 "stat_ex.%s differs: "
316 "cookie:%llu != stat:%llu, "
317 "denying durable reconnect\n",
320 (unsigned long long)cookie_st
->st_ex_dev
,
321 (unsigned long long)fsp_st
->st_ex_dev
));
325 if (cookie_st
->st_ex_ino
!= fsp_st
->st_ex_ino
) {
326 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
327 "stat_ex.%s differs: "
328 "cookie:%llu != stat:%llu, "
329 "denying durable reconnect\n",
332 (unsigned long long)cookie_st
->st_ex_ino
,
333 (unsigned long long)fsp_st
->st_ex_ino
));
337 if (cookie_st
->st_ex_mode
!= fsp_st
->st_ex_mode
) {
338 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
339 "stat_ex.%s differs: "
340 "cookie:%llu != stat:%llu, "
341 "denying durable reconnect\n",
344 (unsigned long long)cookie_st
->st_ex_mode
,
345 (unsigned long long)fsp_st
->st_ex_mode
));
349 if (cookie_st
->st_ex_nlink
!= fsp_st
->st_ex_nlink
) {
350 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
351 "stat_ex.%s differs: "
352 "cookie:%llu != stat:%llu, "
353 "denying durable reconnect\n",
356 (unsigned long long)cookie_st
->st_ex_nlink
,
357 (unsigned long long)fsp_st
->st_ex_nlink
));
361 if (cookie_st
->st_ex_uid
!= fsp_st
->st_ex_uid
) {
362 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
363 "stat_ex.%s differs: "
364 "cookie:%llu != stat:%llu, "
365 "denying durable reconnect\n",
368 (unsigned long long)cookie_st
->st_ex_uid
,
369 (unsigned long long)fsp_st
->st_ex_uid
));
373 if (cookie_st
->st_ex_gid
!= fsp_st
->st_ex_gid
) {
374 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
375 "stat_ex.%s differs: "
376 "cookie:%llu != stat:%llu, "
377 "denying durable reconnect\n",
380 (unsigned long long)cookie_st
->st_ex_gid
,
381 (unsigned long long)fsp_st
->st_ex_gid
));
385 if (cookie_st
->st_ex_rdev
!= fsp_st
->st_ex_rdev
) {
386 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
387 "stat_ex.%s differs: "
388 "cookie:%llu != stat:%llu, "
389 "denying durable reconnect\n",
392 (unsigned long long)cookie_st
->st_ex_rdev
,
393 (unsigned long long)fsp_st
->st_ex_rdev
));
397 if (cookie_st
->st_ex_size
!= fsp_st
->st_ex_size
) {
398 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
399 "stat_ex.%s differs: "
400 "cookie:%llu != stat:%llu, "
401 "denying durable reconnect\n",
404 (unsigned long long)cookie_st
->st_ex_size
,
405 (unsigned long long)fsp_st
->st_ex_size
));
409 ret
= timespec_compare(&cookie_st
->st_ex_atime
,
410 &fsp_st
->st_ex_atime
);
412 struct timeval tc
, ts
;
413 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_atime
);
414 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_atime
);
416 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
417 "stat_ex.%s differs: "
418 "cookie:'%s' != stat:'%s', "
419 "denying durable reconnect\n",
422 timeval_string(talloc_tos(), &tc
, true),
423 timeval_string(talloc_tos(), &ts
, true)));
427 ret
= timespec_compare(&cookie_st
->st_ex_mtime
,
428 &fsp_st
->st_ex_mtime
);
430 struct timeval tc
, ts
;
431 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_mtime
);
432 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_mtime
);
434 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
435 "stat_ex.%s differs: "
436 "cookie:'%s' != stat:'%s', "
437 "denying durable reconnect\n",
440 timeval_string(talloc_tos(), &tc
, true),
441 timeval_string(talloc_tos(), &ts
, true)));
445 ret
= timespec_compare(&cookie_st
->st_ex_ctime
,
446 &fsp_st
->st_ex_ctime
);
448 struct timeval tc
, ts
;
449 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_ctime
);
450 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_ctime
);
452 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
453 "stat_ex.%s differs: "
454 "cookie:'%s' != stat:'%s', "
455 "denying durable reconnect\n",
458 timeval_string(talloc_tos(), &tc
, true),
459 timeval_string(talloc_tos(), &ts
, true)));
463 ret
= timespec_compare(&cookie_st
->st_ex_btime
,
464 &fsp_st
->st_ex_btime
);
466 struct timeval tc
, ts
;
467 tc
= convert_timespec_to_timeval(cookie_st
->st_ex_btime
);
468 ts
= convert_timespec_to_timeval(fsp_st
->st_ex_btime
);
470 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
471 "stat_ex.%s differs: "
472 "cookie:'%s' != stat:'%s', "
473 "denying durable reconnect\n",
476 timeval_string(talloc_tos(), &tc
, true),
477 timeval_string(talloc_tos(), &ts
, true)));
481 if (cookie_st
->st_ex_calculated_birthtime
!=
482 fsp_st
->st_ex_calculated_birthtime
)
484 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
485 "stat_ex.%s differs: "
486 "cookie:%llu != stat:%llu, "
487 "denying durable reconnect\n",
489 "st_ex_calculated_birthtime",
490 (unsigned long long)cookie_st
->st_ex_calculated_birthtime
,
491 (unsigned long long)fsp_st
->st_ex_calculated_birthtime
));
495 if (cookie_st
->st_ex_blksize
!= fsp_st
->st_ex_blksize
) {
496 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
497 "stat_ex.%s differs: "
498 "cookie:%llu != stat:%llu, "
499 "denying durable reconnect\n",
502 (unsigned long long)cookie_st
->st_ex_blksize
,
503 (unsigned long long)fsp_st
->st_ex_blksize
));
507 if (cookie_st
->st_ex_blocks
!= fsp_st
->st_ex_blocks
) {
508 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
509 "stat_ex.%s differs: "
510 "cookie:%llu != stat:%llu, "
511 "denying durable reconnect\n",
514 (unsigned long long)cookie_st
->st_ex_blocks
,
515 (unsigned long long)fsp_st
->st_ex_blocks
));
519 if (cookie_st
->st_ex_flags
!= fsp_st
->st_ex_flags
) {
520 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
521 "stat_ex.%s differs: "
522 "cookie:%llu != stat:%llu, "
523 "denying durable reconnect\n",
526 (unsigned long long)cookie_st
->st_ex_flags
,
527 (unsigned long long)fsp_st
->st_ex_flags
));
531 if (cookie_st
->st_ex_mask
!= fsp_st
->st_ex_mask
) {
532 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
533 "stat_ex.%s differs: "
534 "cookie:%llu != stat:%llu, "
535 "denying durable reconnect\n",
538 (unsigned long long)cookie_st
->st_ex_mask
,
539 (unsigned long long)fsp_st
->st_ex_mask
));
543 if (cookie_st
->vfs_private
!= fsp_st
->vfs_private
) {
544 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
545 "stat_ex.%s differs: "
546 "cookie:%llu != stat:%llu, "
547 "denying durable reconnect\n",
550 (unsigned long long)cookie_st
->vfs_private
,
551 (unsigned long long)fsp_st
->vfs_private
));
558 NTSTATUS
vfs_default_durable_reconnect(struct connection_struct
*conn
,
559 struct smb_request
*smb1req
,
560 struct smbXsrv_open
*op
,
561 const DATA_BLOB old_cookie
,
563 files_struct
**result
,
564 DATA_BLOB
*new_cookie
)
566 struct share_mode_lock
*lck
;
567 struct share_mode_entry
*e
;
568 struct files_struct
*fsp
= NULL
;
573 struct file_id file_id
;
574 struct smb_filename
*smb_fname
= NULL
;
575 enum ndr_err_code ndr_err
;
576 struct vfs_default_durable_cookie cookie
;
577 DATA_BLOB new_cookie_blob
= data_blob_null
;
580 *new_cookie
= data_blob_null
;
582 if (!lp_durable_handles(SNUM(conn
))) {
583 return NT_STATUS_NOT_SUPPORTED
;
587 * the checks for kernel oplocks
588 * and similar things are done
589 * in the vfs_default_durable_cookie()
595 ndr_err
= ndr_pull_struct_blob(&old_cookie
, talloc_tos(), &cookie
,
596 (ndr_pull_flags_fn_t
)ndr_pull_vfs_default_durable_cookie
);
597 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
598 status
= ndr_map_error2ntstatus(ndr_err
);
602 if (strcmp(cookie
.magic
, VFS_DEFAULT_DURABLE_COOKIE_MAGIC
) != 0) {
603 return NT_STATUS_INVALID_PARAMETER
;
606 if (cookie
.version
!= VFS_DEFAULT_DURABLE_COOKIE_VERSION
) {
607 return NT_STATUS_INVALID_PARAMETER
;
610 if (!cookie
.allow_reconnect
) {
611 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
614 if (strcmp(cookie
.servicepath
, conn
->connectpath
) != 0) {
615 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
618 /* Create an smb_filename with stream_name == NULL. */
619 status
= create_synthetic_smb_fname(talloc_tos(),
623 if (!NT_STATUS_IS_OK(status
)) {
627 ret
= SMB_VFS_LSTAT(conn
, smb_fname
);
629 status
= map_nt_error_from_unix_common(errno
);
630 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
631 smb_fname_str_dbg(smb_fname
),
636 if (!S_ISREG(smb_fname
->st
.st_ex_mode
)) {
637 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
640 file_id
= vfs_file_id_from_sbuf(conn
, &smb_fname
->st
);
641 if (!file_id_equal(&cookie
.id
, &file_id
)) {
642 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
646 * 1. check entry in locking.tdb
649 lck
= get_existing_share_mode_lock(mem_ctx
, file_id
);
651 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
652 "not obtained from db\n"));
653 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
656 if (lck
->data
->num_share_modes
== 0) {
657 DEBUG(1, ("vfs_default_durable_reconnect: Error: no share-mode "
658 "entry in existing share mode lock\n"));
660 return NT_STATUS_INTERNAL_DB_ERROR
;
663 if (lck
->data
->num_share_modes
> 1) {
665 * It can't be durable if there is more than one handle
668 DEBUG(5, ("vfs_default_durable_reconnect: more than one "
669 "share-mode entry - can not be durable\n"));
671 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
674 e
= &lck
->data
->share_modes
[0];
676 if (!server_id_is_disconnected(&e
->pid
)) {
677 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
678 "reconnect for handle that was not marked "
679 "disconnected (e.g. smbd or cluster node died)\n"));
681 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
684 if (e
->share_file_id
!= op
->global
->open_persistent_id
) {
685 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
686 "share_file_id changed %llu != %llu"
687 "(e.g. another client had opened the file)\n",
688 (unsigned long long)e
->share_file_id
,
689 (unsigned long long)op
->global
->open_persistent_id
));
691 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
694 if ((e
->access_mask
& (FILE_WRITE_DATA
|FILE_APPEND_DATA
)) &&
697 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
698 "share[%s] is not writeable anymore\n",
699 lp_servicename(talloc_tos(), SNUM(conn
))));
701 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
706 * add scavenger timer functionality
708 * For now we always allow the reconnect
711 expire_time
= op
->global
->disconnect_time
;
712 expire_time
+= NTTIME_MAGIC(op
->global
->durable_timeout_msec
);
714 //TODO reopen and close before telling the client...
719 * 2. proceed with opening file
722 status
= fsp_new(conn
, conn
, &fsp
);
723 if (!NT_STATUS_IS_OK(status
)) {
724 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
725 "new fsp: %s\n", nt_errstr(status
)));
730 fsp
->fh
->private_options
= e
->private_options
;
731 fsp
->fh
->gen_id
= smbXsrv_open_hash(op
);
732 fsp
->file_id
= file_id
;
733 fsp
->file_pid
= smb1req
->smbpid
;
734 fsp
->vuid
= smb1req
->vuid
;
735 fsp
->open_time
= e
->time
;
736 fsp
->access_mask
= e
->access_mask
;
737 fsp
->share_access
= e
->share_access
;
738 fsp
->can_read
= ((fsp
->access_mask
& (FILE_READ_DATA
)) != 0);
739 fsp
->can_write
= ((fsp
->access_mask
& (FILE_WRITE_DATA
|FILE_APPEND_DATA
)) != 0);
743 * Do we need to store the modified flag in the DB?
744 * How to handle update_write_time and friends
745 * during a disconnected client on a durable handle?
747 fsp
->modified
= false;
749 * no durables for directories
751 fsp
->is_directory
= false;
753 * For normal files, can_lock == !is_directory
755 fsp
->can_lock
= true;
757 * We do not support aio write behind for smb2
759 fsp
->aio_write_behind
= false;
760 fsp
->oplock_type
= e
->op_type
;
762 fsp
->initial_allocation_size
= cookie
.initial_allocation_size
;
763 fsp
->fh
->position_information
= cookie
.position_information
;
764 fsp
->update_write_time_triggered
= cookie
.update_write_time_triggered
;
765 fsp
->update_write_time_on_close
= cookie
.update_write_time_on_close
;
766 fsp
->write_time_forced
= cookie
.write_time_forced
;
767 fsp
->close_write_time
= cookie
.close_write_time
;
769 status
= fsp_set_smb_fname(fsp
, smb_fname
);
770 if (!NT_STATUS_IS_OK(status
)) {
773 DEBUG(0, ("vfs_default_durable_reconnect: "
774 "fsp_set_smb_fname failed: %s\n",
782 e
->pid
= messaging_server_id(conn
->sconn
->msg_ctx
);
783 e
->op_mid
= smb1req
->mid
;
784 e
->share_file_id
= fsp
->fh
->gen_id
;
786 ok
= brl_reconnect_disconnected(fsp
);
788 status
= NT_STATUS_INTERNAL_ERROR
;
789 DEBUG(1, ("vfs_default_durable_reconnect: "
790 "failed to reopen brlocks: %s\n",
799 * TODO: properly calculate open flags
801 if (fsp
->can_write
&& fsp
->can_read
) {
803 } else if (fsp
->can_write
) {
805 } else if (fsp
->can_read
) {
809 status
= fd_open(conn
, fsp
, flags
, 0 /* mode */);
810 if (!NT_STATUS_IS_OK(status
)) {
812 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
813 "file: %s\n", nt_errstr(status
)));
820 * We now check the stat info stored in the cookie against
821 * the current stat data from the file we just opened.
822 * If any detail differs, we deny the durable reconnect,
823 * because in that case it is very likely that someone
824 * opened the file while the handle was disconnected,
825 * which has to be interpreted as an oplock break.
828 ret
= SMB_VFS_FSTAT(fsp
, &fsp
->fsp_name
->st
);
830 status
= map_nt_error_from_unix_common(errno
);
831 DEBUG(1, ("Unable to fstat stream: %s => %s\n",
832 smb_fname_str_dbg(smb_fname
),
834 ret
= SMB_VFS_CLOSE(fsp
);
836 DEBUG(0, ("vfs_default_durable_reconnect: "
837 "SMB_VFS_CLOSE failed (%s) - leaking file "
838 "descriptor\n", strerror(errno
)));
846 if (!S_ISREG(fsp
->fsp_name
->st
.st_ex_mode
)) {
847 ret
= SMB_VFS_CLOSE(fsp
);
849 DEBUG(0, ("vfs_default_durable_reconnect: "
850 "SMB_VFS_CLOSE failed (%s) - leaking file "
851 "descriptor\n", strerror(errno
)));
856 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
859 file_id
= vfs_file_id_from_sbuf(conn
, &fsp
->fsp_name
->st
);
860 if (!file_id_equal(&cookie
.id
, &file_id
)) {
861 ret
= SMB_VFS_CLOSE(fsp
);
863 DEBUG(0, ("vfs_default_durable_reconnect: "
864 "SMB_VFS_CLOSE failed (%s) - leaking file "
865 "descriptor\n", strerror(errno
)));
870 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
873 ok
= vfs_default_durable_reconnect_check_stat(&cookie
.stat_info
,
877 ret
= SMB_VFS_CLOSE(fsp
);
879 DEBUG(0, ("vfs_default_durable_reconnect: "
880 "SMB_VFS_CLOSE failed (%s) - leaking file "
881 "descriptor\n", strerror(errno
)));
886 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
889 status
= set_file_oplock(fsp
, e
->op_type
);
890 if (!NT_STATUS_IS_OK(status
)) {
891 DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
892 "after opening file: %s\n", nt_errstr(status
)));
893 ret
= SMB_VFS_CLOSE(fsp
);
895 DEBUG(0, ("vfs_default_durable_reconnect: "
896 "SMB_VFS_CLOSE failed (%s) - leaking file "
897 "descriptor\n", strerror(errno
)));
905 status
= vfs_default_durable_cookie(fsp
, mem_ctx
, &new_cookie_blob
);
906 if (!NT_STATUS_IS_OK(status
)) {
908 DEBUG(1, ("vfs_default_durable_reconnect: "
909 "vfs_default_durable_cookie - %s\n",
916 smb1req
->chain_fsp
= fsp
;
917 smb1req
->smb2req
->compat_chain_fsp
= fsp
;
919 DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
923 * release the sharemode lock: this writes the changes
925 lck
->data
->modified
= true;
929 *new_cookie
= new_cookie_blob
;