wafsamba: remove unused variable from copy_and_fix_python_path
[Samba.git] / source3 / smbd / durable.c
blobc3d0a6fd58b06bb6514bf99cb6151eea7684da50
1 /*
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/>.
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "smbd/smbd.h"
26 #include "smbd/globals.h"
27 #include "libcli/security/security.h"
28 #include "messages.h"
29 #include "librpc/gen_ndr/ndr_open_files.h"
30 #include "serverid.h"
31 #include "fake_file.h"
33 NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
34 TALLOC_CTX *mem_ctx,
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
82 * on streams for now.
84 return NT_STATUS_NOT_SUPPORTED;
87 if (is_fake_file(fsp->fsp_name)) {
89 * We do not support durable handles
90 * on fake files.
92 return NT_STATUS_NOT_SUPPORTED;
95 ZERO_STRUCT(cookie);
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;
125 ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
126 (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
127 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
128 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
129 return status;
132 return NT_STATUS_OK;
135 NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
136 const DATA_BLOB old_cookie,
137 TALLOC_CTX *mem_ctx,
138 DATA_BLOB *new_cookie)
140 struct connection_struct *conn = fsp->conn;
141 NTSTATUS status;
142 enum ndr_err_code ndr_err;
143 struct vfs_default_durable_cookie cookie;
144 DATA_BLOB new_cookie_blob = data_blob_null;
145 struct share_mode_lock *lck;
146 bool ok;
148 *new_cookie = data_blob_null;
150 ZERO_STRUCT(cookie);
152 ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
153 (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
154 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
155 status = ndr_map_error2ntstatus(ndr_err);
156 return status;
159 if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
160 return NT_STATUS_INVALID_PARAMETER;
163 if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
164 return NT_STATUS_INVALID_PARAMETER;
167 if (!file_id_equal(&fsp->file_id, &cookie.id)) {
168 return NT_STATUS_INVALID_PARAMETER;
171 if (!BATCH_OPLOCK_TYPE(fsp->oplock_type)) {
172 return NT_STATUS_NOT_SUPPORTED;
176 * For now let it be simple and do not keep
177 * delete on close files durable open
179 if (fsp->initial_delete_on_close) {
180 return NT_STATUS_NOT_SUPPORTED;
182 if (fsp->delete_on_close) {
183 return NT_STATUS_NOT_SUPPORTED;
186 if (!VALID_STAT(fsp->fsp_name->st)) {
187 return NT_STATUS_NOT_SUPPORTED;
190 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
191 return NT_STATUS_NOT_SUPPORTED;
194 /* Ensure any pending write time updates are done. */
195 if (fsp->update_write_time_event) {
196 update_write_time_handler(fsp->conn->sconn->ev_ctx,
197 fsp->update_write_time_event,
198 timeval_current(),
199 (void *)fsp);
203 * The above checks are done in mark_share_mode_disconnected() too
204 * but we want to avoid getting the lock if possible
206 lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
207 if (lck != NULL) {
208 struct smb_file_time ft;
210 ZERO_STRUCT(ft);
212 if (fsp->write_time_forced) {
213 ft.mtime = lck->data->changed_write_time;
214 } else if (fsp->update_write_time_on_close) {
215 if (null_timespec(fsp->close_write_time)) {
216 ft.mtime = timespec_current();
217 } else {
218 ft.mtime = fsp->close_write_time;
222 if (!null_timespec(ft.mtime)) {
223 round_timespec(conn->ts_res, &ft.mtime);
224 file_ntimes(conn, fsp->fsp_name, &ft);
227 ok = mark_share_mode_disconnected(lck, fsp);
228 if (!ok) {
229 TALLOC_FREE(lck);
232 if (lck != NULL) {
233 ok = brl_mark_disconnected(fsp);
234 if (!ok) {
235 TALLOC_FREE(lck);
238 if (lck == NULL) {
239 return NT_STATUS_NOT_SUPPORTED;
241 TALLOC_FREE(lck);
243 status = vfs_stat_fsp(fsp);
244 if (!NT_STATUS_IS_OK(status)) {
245 return status;
248 ZERO_STRUCT(cookie);
249 cookie.allow_reconnect = true;
250 cookie.id = fsp->file_id;
251 cookie.servicepath = conn->connectpath;
252 cookie.base_name = fsp->fsp_name->base_name;
253 cookie.initial_allocation_size = fsp->initial_allocation_size;
254 cookie.position_information = fsp->fh->position_information;
255 cookie.update_write_time_triggered = fsp->update_write_time_triggered;
256 cookie.update_write_time_on_close = fsp->update_write_time_on_close;
257 cookie.write_time_forced = fsp->write_time_forced;
258 cookie.close_write_time = fsp->close_write_time;
260 cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
261 cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
262 cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
263 cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
264 cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
265 cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
266 cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
267 cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
268 cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
269 cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
270 cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
271 cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
272 cookie.stat_info.st_ex_calculated_birthtime = fsp->fsp_name->st.st_ex_calculated_birthtime;
273 cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
274 cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
275 cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
276 cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
278 ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
279 (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
280 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
281 status = ndr_map_error2ntstatus(ndr_err);
282 return status;
285 status = fd_close(fsp);
286 if (!NT_STATUS_IS_OK(status)) {
287 data_blob_free(&new_cookie_blob);
288 return status;
291 *new_cookie = new_cookie_blob;
292 return NT_STATUS_OK;
297 * Check whether a cookie-stored struct info is the same
298 * as a given SMB_STRUCT_STAT, as coming with the fsp.
300 static bool vfs_default_durable_reconnect_check_stat(
301 struct vfs_default_durable_stat *cookie_st,
302 SMB_STRUCT_STAT *fsp_st,
303 const char *name)
305 int ret;
307 if (cookie_st->st_ex_dev != fsp_st->st_ex_dev) {
308 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
309 "stat_ex.%s differs: "
310 "cookie:%llu != stat:%llu, "
311 "denying durable reconnect\n",
312 name,
313 "st_ex_dev",
314 (unsigned long long)cookie_st->st_ex_dev,
315 (unsigned long long)fsp_st->st_ex_dev));
316 return false;
319 if (cookie_st->st_ex_ino != fsp_st->st_ex_ino) {
320 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
321 "stat_ex.%s differs: "
322 "cookie:%llu != stat:%llu, "
323 "denying durable reconnect\n",
324 name,
325 "st_ex_ino",
326 (unsigned long long)cookie_st->st_ex_ino,
327 (unsigned long long)fsp_st->st_ex_ino));
328 return false;
331 if (cookie_st->st_ex_mode != fsp_st->st_ex_mode) {
332 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
333 "stat_ex.%s differs: "
334 "cookie:%llu != stat:%llu, "
335 "denying durable reconnect\n",
336 name,
337 "st_ex_mode",
338 (unsigned long long)cookie_st->st_ex_mode,
339 (unsigned long long)fsp_st->st_ex_mode));
340 return false;
343 if (cookie_st->st_ex_nlink != fsp_st->st_ex_nlink) {
344 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
345 "stat_ex.%s differs: "
346 "cookie:%llu != stat:%llu, "
347 "denying durable reconnect\n",
348 name,
349 "st_ex_nlink",
350 (unsigned long long)cookie_st->st_ex_nlink,
351 (unsigned long long)fsp_st->st_ex_nlink));
352 return false;
355 if (cookie_st->st_ex_uid != fsp_st->st_ex_uid) {
356 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
357 "stat_ex.%s differs: "
358 "cookie:%llu != stat:%llu, "
359 "denying durable reconnect\n",
360 name,
361 "st_ex_uid",
362 (unsigned long long)cookie_st->st_ex_uid,
363 (unsigned long long)fsp_st->st_ex_uid));
364 return false;
367 if (cookie_st->st_ex_gid != fsp_st->st_ex_gid) {
368 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
369 "stat_ex.%s differs: "
370 "cookie:%llu != stat:%llu, "
371 "denying durable reconnect\n",
372 name,
373 "st_ex_gid",
374 (unsigned long long)cookie_st->st_ex_gid,
375 (unsigned long long)fsp_st->st_ex_gid));
376 return false;
379 if (cookie_st->st_ex_rdev != fsp_st->st_ex_rdev) {
380 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
381 "stat_ex.%s differs: "
382 "cookie:%llu != stat:%llu, "
383 "denying durable reconnect\n",
384 name,
385 "st_ex_rdev",
386 (unsigned long long)cookie_st->st_ex_rdev,
387 (unsigned long long)fsp_st->st_ex_rdev));
388 return false;
391 if (cookie_st->st_ex_size != fsp_st->st_ex_size) {
392 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
393 "stat_ex.%s differs: "
394 "cookie:%llu != stat:%llu, "
395 "denying durable reconnect\n",
396 name,
397 "st_ex_size",
398 (unsigned long long)cookie_st->st_ex_size,
399 (unsigned long long)fsp_st->st_ex_size));
400 return false;
403 ret = timespec_compare(&cookie_st->st_ex_atime,
404 &fsp_st->st_ex_atime);
405 if (ret != 0) {
406 struct timeval tc, ts;
407 tc = convert_timespec_to_timeval(cookie_st->st_ex_atime);
408 ts = convert_timespec_to_timeval(fsp_st->st_ex_atime);
410 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
411 "stat_ex.%s differs: "
412 "cookie:'%s' != stat:'%s', "
413 "denying durable reconnect\n",
414 name,
415 "st_ex_atime",
416 timeval_string(talloc_tos(), &tc, true),
417 timeval_string(talloc_tos(), &ts, true)));
418 return false;
421 ret = timespec_compare(&cookie_st->st_ex_mtime,
422 &fsp_st->st_ex_mtime);
423 if (ret != 0) {
424 struct timeval tc, ts;
425 tc = convert_timespec_to_timeval(cookie_st->st_ex_mtime);
426 ts = convert_timespec_to_timeval(fsp_st->st_ex_mtime);
428 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
429 "stat_ex.%s differs: "
430 "cookie:'%s' != stat:'%s', "
431 "denying durable reconnect\n",
432 name,
433 "st_ex_mtime",
434 timeval_string(talloc_tos(), &tc, true),
435 timeval_string(talloc_tos(), &ts, true)));
436 return false;
439 ret = timespec_compare(&cookie_st->st_ex_ctime,
440 &fsp_st->st_ex_ctime);
441 if (ret != 0) {
442 struct timeval tc, ts;
443 tc = convert_timespec_to_timeval(cookie_st->st_ex_ctime);
444 ts = convert_timespec_to_timeval(fsp_st->st_ex_ctime);
446 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
447 "stat_ex.%s differs: "
448 "cookie:'%s' != stat:'%s', "
449 "denying durable reconnect\n",
450 name,
451 "st_ex_ctime",
452 timeval_string(talloc_tos(), &tc, true),
453 timeval_string(talloc_tos(), &ts, true)));
454 return false;
457 ret = timespec_compare(&cookie_st->st_ex_btime,
458 &fsp_st->st_ex_btime);
459 if (ret != 0) {
460 struct timeval tc, ts;
461 tc = convert_timespec_to_timeval(cookie_st->st_ex_btime);
462 ts = convert_timespec_to_timeval(fsp_st->st_ex_btime);
464 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
465 "stat_ex.%s differs: "
466 "cookie:'%s' != stat:'%s', "
467 "denying durable reconnect\n",
468 name,
469 "st_ex_btime",
470 timeval_string(talloc_tos(), &tc, true),
471 timeval_string(talloc_tos(), &ts, true)));
472 return false;
475 if (cookie_st->st_ex_calculated_birthtime !=
476 fsp_st->st_ex_calculated_birthtime)
478 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
479 "stat_ex.%s differs: "
480 "cookie:%llu != stat:%llu, "
481 "denying durable reconnect\n",
482 name,
483 "st_ex_calculated_birthtime",
484 (unsigned long long)cookie_st->st_ex_calculated_birthtime,
485 (unsigned long long)fsp_st->st_ex_calculated_birthtime));
486 return false;
489 if (cookie_st->st_ex_blksize != fsp_st->st_ex_blksize) {
490 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
491 "stat_ex.%s differs: "
492 "cookie:%llu != stat:%llu, "
493 "denying durable reconnect\n",
494 name,
495 "st_ex_blksize",
496 (unsigned long long)cookie_st->st_ex_blksize,
497 (unsigned long long)fsp_st->st_ex_blksize));
498 return false;
501 if (cookie_st->st_ex_blocks != fsp_st->st_ex_blocks) {
502 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
503 "stat_ex.%s differs: "
504 "cookie:%llu != stat:%llu, "
505 "denying durable reconnect\n",
506 name,
507 "st_ex_blocks",
508 (unsigned long long)cookie_st->st_ex_blocks,
509 (unsigned long long)fsp_st->st_ex_blocks));
510 return false;
513 if (cookie_st->st_ex_flags != fsp_st->st_ex_flags) {
514 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
515 "stat_ex.%s differs: "
516 "cookie:%llu != stat:%llu, "
517 "denying durable reconnect\n",
518 name,
519 "st_ex_flags",
520 (unsigned long long)cookie_st->st_ex_flags,
521 (unsigned long long)fsp_st->st_ex_flags));
522 return false;
525 if (cookie_st->st_ex_mask != fsp_st->st_ex_mask) {
526 DEBUG(1, ("vfs_default_durable_reconnect (%s): "
527 "stat_ex.%s differs: "
528 "cookie:%llu != stat:%llu, "
529 "denying durable reconnect\n",
530 name,
531 "st_ex_mask",
532 (unsigned long long)cookie_st->st_ex_mask,
533 (unsigned long long)fsp_st->st_ex_mask));
534 return false;
537 return true;
540 NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
541 struct smb_request *smb1req,
542 struct smbXsrv_open *op,
543 const DATA_BLOB old_cookie,
544 TALLOC_CTX *mem_ctx,
545 files_struct **result,
546 DATA_BLOB *new_cookie)
548 struct share_mode_lock *lck;
549 struct share_mode_entry *e;
550 struct files_struct *fsp = NULL;
551 NTSTATUS status;
552 bool ok;
553 int ret;
554 int flags = 0;
555 struct file_id file_id;
556 struct smb_filename *smb_fname = NULL;
557 enum ndr_err_code ndr_err;
558 struct vfs_default_durable_cookie cookie;
559 DATA_BLOB new_cookie_blob = data_blob_null;
561 *result = NULL;
562 *new_cookie = data_blob_null;
564 if (!lp_durable_handles(SNUM(conn))) {
565 return NT_STATUS_NOT_SUPPORTED;
569 * the checks for kernel oplocks
570 * and similar things are done
571 * in the vfs_default_durable_cookie()
572 * call below.
575 ZERO_STRUCT(cookie);
577 ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
578 (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
579 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
580 status = ndr_map_error2ntstatus(ndr_err);
581 return status;
584 if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
585 return NT_STATUS_INVALID_PARAMETER;
588 if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
589 return NT_STATUS_INVALID_PARAMETER;
592 if (!cookie.allow_reconnect) {
593 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
596 if (strcmp(cookie.servicepath, conn->connectpath) != 0) {
597 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
600 /* Create an smb_filename with stream_name == NULL. */
601 smb_fname = synthetic_smb_fname(talloc_tos(), cookie.base_name,
602 NULL, NULL);
603 if (smb_fname == NULL) {
604 return NT_STATUS_NO_MEMORY;
607 ret = SMB_VFS_LSTAT(conn, smb_fname);
608 if (ret == -1) {
609 status = map_nt_error_from_unix_common(errno);
610 DEBUG(1, ("Unable to lstat stream: %s => %s\n",
611 smb_fname_str_dbg(smb_fname),
612 nt_errstr(status)));
613 return status;
616 if (!S_ISREG(smb_fname->st.st_ex_mode)) {
617 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
620 file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
621 if (!file_id_equal(&cookie.id, &file_id)) {
622 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
626 * 1. check entry in locking.tdb
629 lck = get_existing_share_mode_lock(mem_ctx, file_id);
630 if (lck == NULL) {
631 DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
632 "not obtained from db\n"));
633 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
636 if (lck->data->num_share_modes == 0) {
637 DEBUG(1, ("vfs_default_durable_reconnect: Error: no share-mode "
638 "entry in existing share mode lock\n"));
639 TALLOC_FREE(lck);
640 return NT_STATUS_INTERNAL_DB_ERROR;
643 if (lck->data->num_share_modes > 1) {
645 * It can't be durable if there is more than one handle
646 * on the file.
648 DEBUG(5, ("vfs_default_durable_reconnect: more than one "
649 "share-mode entry - can not be durable\n"));
650 TALLOC_FREE(lck);
651 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
654 e = &lck->data->share_modes[0];
656 if (!server_id_is_disconnected(&e->pid)) {
657 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
658 "reconnect for handle that was not marked "
659 "disconnected (e.g. smbd or cluster node died)\n"));
660 TALLOC_FREE(lck);
661 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
664 if (e->share_file_id != op->global->open_persistent_id) {
665 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
666 "share_file_id changed %llu != %llu"
667 "(e.g. another client had opened the file)\n",
668 (unsigned long long)e->share_file_id,
669 (unsigned long long)op->global->open_persistent_id));
670 TALLOC_FREE(lck);
671 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
674 if ((e->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
675 !CAN_WRITE(conn))
677 DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
678 "share[%s] is not writeable anymore\n",
679 lp_servicename(talloc_tos(), SNUM(conn))));
680 TALLOC_FREE(lck);
681 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
685 * 2. proceed with opening file
688 status = fsp_new(conn, conn, &fsp);
689 if (!NT_STATUS_IS_OK(status)) {
690 DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
691 "new fsp: %s\n", nt_errstr(status)));
692 TALLOC_FREE(lck);
693 return status;
696 fsp->fh->private_options = e->private_options;
697 fsp->fh->gen_id = smbXsrv_open_hash(op);
698 fsp->file_id = file_id;
699 fsp->file_pid = smb1req->smbpid;
700 fsp->vuid = smb1req->vuid;
701 fsp->open_time = e->time;
702 fsp->access_mask = e->access_mask;
703 fsp->share_access = e->share_access;
704 fsp->can_read = ((fsp->access_mask & (FILE_READ_DATA)) != 0);
705 fsp->can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
708 * TODO:
709 * Do we need to store the modified flag in the DB?
711 fsp->modified = false;
713 * no durables for directories
715 fsp->is_directory = false;
717 * For normal files, can_lock == !is_directory
719 fsp->can_lock = true;
721 * We do not support aio write behind for smb2
723 fsp->aio_write_behind = false;
724 fsp->oplock_type = e->op_type;
726 fsp->initial_allocation_size = cookie.initial_allocation_size;
727 fsp->fh->position_information = cookie.position_information;
728 fsp->update_write_time_triggered = cookie.update_write_time_triggered;
729 fsp->update_write_time_on_close = cookie.update_write_time_on_close;
730 fsp->write_time_forced = cookie.write_time_forced;
731 fsp->close_write_time = cookie.close_write_time;
733 status = fsp_set_smb_fname(fsp, smb_fname);
734 if (!NT_STATUS_IS_OK(status)) {
735 TALLOC_FREE(lck);
736 fsp_free(fsp);
737 DEBUG(0, ("vfs_default_durable_reconnect: "
738 "fsp_set_smb_fname failed: %s\n",
739 nt_errstr(status)));
740 return status;
743 op->compat = fsp;
744 fsp->op = op;
746 e->pid = messaging_server_id(conn->sconn->msg_ctx);
747 e->op_mid = smb1req->mid;
748 e->share_file_id = fsp->fh->gen_id;
750 ok = brl_reconnect_disconnected(fsp);
751 if (!ok) {
752 status = NT_STATUS_INTERNAL_ERROR;
753 DEBUG(1, ("vfs_default_durable_reconnect: "
754 "failed to reopen brlocks: %s\n",
755 nt_errstr(status)));
756 TALLOC_FREE(lck);
757 op->compat = NULL;
758 fsp_free(fsp);
759 return status;
763 * TODO: properly calculate open flags
765 if (fsp->can_write && fsp->can_read) {
766 flags = O_RDWR;
767 } else if (fsp->can_write) {
768 flags = O_WRONLY;
769 } else if (fsp->can_read) {
770 flags = O_RDONLY;
773 status = fd_open(conn, fsp, flags, 0 /* mode */);
774 if (!NT_STATUS_IS_OK(status)) {
775 TALLOC_FREE(lck);
776 DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
777 "file: %s\n", nt_errstr(status)));
778 op->compat = NULL;
779 fsp_free(fsp);
780 return status;
784 * We now check the stat info stored in the cookie against
785 * the current stat data from the file we just opened.
786 * If any detail differs, we deny the durable reconnect,
787 * because in that case it is very likely that someone
788 * opened the file while the handle was disconnected,
789 * which has to be interpreted as an oplock break.
792 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
793 if (ret == -1) {
794 status = map_nt_error_from_unix_common(errno);
795 DEBUG(1, ("Unable to fstat stream: %s => %s\n",
796 smb_fname_str_dbg(smb_fname),
797 nt_errstr(status)));
798 ret = SMB_VFS_CLOSE(fsp);
799 if (ret == -1) {
800 DEBUG(0, ("vfs_default_durable_reconnect: "
801 "SMB_VFS_CLOSE failed (%s) - leaking file "
802 "descriptor\n", strerror(errno)));
804 TALLOC_FREE(lck);
805 op->compat = NULL;
806 fsp_free(fsp);
807 return status;
810 if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
811 ret = SMB_VFS_CLOSE(fsp);
812 if (ret == -1) {
813 DEBUG(0, ("vfs_default_durable_reconnect: "
814 "SMB_VFS_CLOSE failed (%s) - leaking file "
815 "descriptor\n", strerror(errno)));
817 TALLOC_FREE(lck);
818 op->compat = NULL;
819 fsp_free(fsp);
820 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
823 file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
824 if (!file_id_equal(&cookie.id, &file_id)) {
825 ret = SMB_VFS_CLOSE(fsp);
826 if (ret == -1) {
827 DEBUG(0, ("vfs_default_durable_reconnect: "
828 "SMB_VFS_CLOSE failed (%s) - leaking file "
829 "descriptor\n", strerror(errno)));
831 TALLOC_FREE(lck);
832 op->compat = NULL;
833 fsp_free(fsp);
834 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
837 ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info,
838 &fsp->fsp_name->st,
839 fsp_str_dbg(fsp));
840 if (!ok) {
841 ret = SMB_VFS_CLOSE(fsp);
842 if (ret == -1) {
843 DEBUG(0, ("vfs_default_durable_reconnect: "
844 "SMB_VFS_CLOSE failed (%s) - leaking file "
845 "descriptor\n", strerror(errno)));
847 TALLOC_FREE(lck);
848 op->compat = NULL;
849 fsp_free(fsp);
850 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
853 status = set_file_oplock(fsp, e->op_type);
854 if (!NT_STATUS_IS_OK(status)) {
855 DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
856 "after opening file: %s\n", nt_errstr(status)));
857 ret = SMB_VFS_CLOSE(fsp);
858 if (ret == -1) {
859 DEBUG(0, ("vfs_default_durable_reconnect: "
860 "SMB_VFS_CLOSE failed (%s) - leaking file "
861 "descriptor\n", strerror(errno)));
863 TALLOC_FREE(lck);
864 op->compat = NULL;
865 fsp_free(fsp);
866 return status;
869 status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob);
870 if (!NT_STATUS_IS_OK(status)) {
871 TALLOC_FREE(lck);
872 DEBUG(1, ("vfs_default_durable_reconnect: "
873 "vfs_default_durable_cookie - %s\n",
874 nt_errstr(status)));
875 op->compat = NULL;
876 fsp_free(fsp);
877 return status;
880 smb1req->chain_fsp = fsp;
881 smb1req->smb2req->compat_chain_fsp = fsp;
883 DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
884 fsp_str_dbg(fsp)));
887 * release the sharemode lock: this writes the changes
889 lck->data->modified = true;
890 TALLOC_FREE(lck);
892 *result = fsp;
893 *new_cookie = new_cookie_blob;
895 return NT_STATUS_OK;