smbd: open_stream_pathref_fsp() does not need a dirfsp
[Samba.git] / source3 / smbd / files.c
blob46207bd7c90351af8977b02f59224d857e93fbce
1 /*
2 Unix SMB/CIFS implementation.
3 Files[] structure handling
4 Copyright (C) Andrew Tridgell 1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "smbd/globals.h"
23 #include "smbd/smbXsrv_open.h"
24 #include "libcli/security/security.h"
25 #include "util_tdb.h"
26 #include "lib/util/bitmap.h"
28 #define FILE_HANDLE_OFFSET 0x1000
30 static NTSTATUS fsp_attach_smb_fname(struct files_struct *fsp,
31 struct smb_filename **_smb_fname);
33 /**
34 * create new fsp to be used for file_new or a durable handle reconnect
36 NTSTATUS fsp_new(struct connection_struct *conn, TALLOC_CTX *mem_ctx,
37 files_struct **result)
39 NTSTATUS status = NT_STATUS_NO_MEMORY;
40 files_struct *fsp = NULL;
41 struct smbd_server_connection *sconn = conn->sconn;
43 fsp = talloc_zero(mem_ctx, struct files_struct);
44 if (fsp == NULL) {
45 goto fail;
49 * This can't be a child of fsp because the file_handle can be ref'd
50 * when doing a dos/fcb open, which will then share the file_handle
51 * across multiple fsps.
53 fsp->fh = fd_handle_create(mem_ctx);
54 if (fsp->fh == NULL) {
55 goto fail;
58 fsp->fsp_flags.use_ofd_locks = !lp_smbd_force_process_locks(SNUM(conn));
59 #ifndef HAVE_OFD_LOCKS
60 fsp->fsp_flags.use_ofd_locks = false;
61 #endif
63 fh_set_refcount(fsp->fh, 1);
64 fsp_set_fd(fsp, -1);
66 fsp->fnum = FNUM_FIELD_INVALID;
67 fsp->conn = conn;
68 fsp->close_write_time = make_omit_timespec();
70 DLIST_ADD(sconn->files, fsp);
71 sconn->num_files += 1;
73 conn->num_files_open++;
75 DBG_INFO("allocated files structure (%u used)\n",
76 (unsigned int)sconn->num_files);
78 *result = fsp;
79 return NT_STATUS_OK;
81 fail:
82 if (fsp != NULL) {
83 TALLOC_FREE(fsp->fh);
85 TALLOC_FREE(fsp);
87 return status;
90 void fsp_set_gen_id(files_struct *fsp)
92 static uint64_t gen_id = 1;
95 * A billion of 64-bit increments per second gives us
96 * more than 500 years of runtime without wrap.
98 gen_id++;
99 fh_set_gen_id(fsp->fh, gen_id);
102 /****************************************************************************
103 Find first available file slot.
104 ****************************************************************************/
106 NTSTATUS fsp_bind_smb(struct files_struct *fsp, struct smb_request *req)
108 struct smbXsrv_open *op = NULL;
109 NTTIME now;
110 NTSTATUS status;
112 if (req == NULL) {
113 DBG_DEBUG("INTERNAL_OPEN_ONLY, skipping smbXsrv_open\n");
114 return NT_STATUS_OK;
117 now = timeval_to_nttime(&fsp->open_time);
119 status = smbXsrv_open_create(req->xconn,
120 fsp->conn->session_info,
121 now,
122 &op);
123 if (!NT_STATUS_IS_OK(status)) {
124 return status;
126 fsp->op = op;
127 op->compat = fsp;
128 fsp->fnum = op->local_id;
130 fsp->mid = req->mid;
131 req->chain_fsp = fsp;
133 DBG_DEBUG("fsp [%s] mid [%" PRIu64"]\n",
134 fsp_str_dbg(fsp), fsp->mid);
136 return NT_STATUS_OK;
139 NTSTATUS file_new(struct smb_request *req, connection_struct *conn,
140 files_struct **result)
142 struct smbd_server_connection *sconn = conn->sconn;
143 files_struct *fsp;
144 NTSTATUS status;
146 status = fsp_new(conn, conn, &fsp);
147 if (!NT_STATUS_IS_OK(status)) {
148 return status;
151 GetTimeOfDay(&fsp->open_time);
153 status = fsp_bind_smb(fsp, req);
154 if (!NT_STATUS_IS_OK(status)) {
155 file_free(NULL, fsp);
156 return status;
159 fsp_set_gen_id(fsp);
162 * Create an smb_filename with "" for the base_name. There are very
163 * few NULL checks, so make sure it's initialized with something. to
164 * be safe until an audit can be done.
166 fsp->fsp_name = synthetic_smb_fname(fsp,
168 NULL,
169 NULL,
172 if (fsp->fsp_name == NULL) {
173 file_free(NULL, fsp);
174 return NT_STATUS_NO_MEMORY;
177 DBG_INFO("new file %s\n", fsp_fnum_dbg(fsp));
179 /* A new fsp invalidates the positive and
180 negative fsp_fi_cache as the new fsp is pushed
181 at the start of the list and we search from
182 a cache hit to the *end* of the list. */
184 ZERO_STRUCT(sconn->fsp_fi_cache);
186 *result = fsp;
187 return NT_STATUS_OK;
190 NTSTATUS create_internal_fsp(connection_struct *conn,
191 const struct smb_filename *smb_fname,
192 struct files_struct **_fsp)
194 struct files_struct *fsp = NULL;
195 NTSTATUS status;
197 status = file_new(NULL, conn, &fsp);
198 if (!NT_STATUS_IS_OK(status)) {
199 return status;
202 status = fsp_set_smb_fname(fsp, smb_fname);
203 if (!NT_STATUS_IS_OK(status)) {
204 file_free(NULL, fsp);
205 return status;
208 *_fsp = fsp;
209 return NT_STATUS_OK;
213 * Create an internal fsp for an *existing* directory.
215 * This should only be used by callers in the VFS that need to control the
216 * opening of the directory. Otherwise use open_internal_dirfsp_at().
218 NTSTATUS create_internal_dirfsp(connection_struct *conn,
219 const struct smb_filename *smb_dname,
220 struct files_struct **_fsp)
222 struct files_struct *fsp = NULL;
223 NTSTATUS status;
225 status = create_internal_fsp(conn, smb_dname, &fsp);
226 if (!NT_STATUS_IS_OK(status)) {
227 return status;
230 fsp->access_mask = FILE_LIST_DIRECTORY;
231 fsp->fsp_flags.is_directory = true;
232 fsp->fsp_flags.is_dirfsp = true;
234 *_fsp = fsp;
235 return NT_STATUS_OK;
239 * Open an internal fsp for an *existing* directory.
241 NTSTATUS open_internal_dirfsp(connection_struct *conn,
242 const struct smb_filename *smb_dname,
243 int open_flags,
244 struct files_struct **_fsp)
246 struct files_struct *fsp = NULL;
247 NTSTATUS status;
249 status = create_internal_dirfsp(conn, smb_dname, &fsp);
250 if (!NT_STATUS_IS_OK(status)) {
251 return status;
254 #ifdef O_DIRECTORY
255 open_flags |= O_DIRECTORY;
256 #endif
257 status = fd_openat(conn->cwd_fsp, fsp->fsp_name, fsp, open_flags, 0);
258 if (!NT_STATUS_IS_OK(status)) {
259 DBG_INFO("Could not open fd for %s (%s)\n",
260 smb_fname_str_dbg(smb_dname),
261 nt_errstr(status));
262 file_free(NULL, fsp);
263 return status;
266 status = vfs_stat_fsp(fsp);
267 if (!NT_STATUS_IS_OK(status)) {
268 file_free(NULL, fsp);
269 return status;
272 if (!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
273 DBG_ERR("%s is not a directory!\n",
274 smb_fname_str_dbg(smb_dname));
275 file_free(NULL, fsp);
276 return NT_STATUS_NOT_A_DIRECTORY;
279 fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
281 *_fsp = fsp;
282 return NT_STATUS_OK;
286 * Convert a pathref dirfsp into a real fsp. No need to do any cwd
287 * tricks, we just open ".".
289 NTSTATUS openat_internal_dir_from_pathref(
290 struct files_struct *dirfsp,
291 int open_flags,
292 struct files_struct **_fsp)
294 struct connection_struct *conn = dirfsp->conn;
295 struct smb_filename *smb_dname = dirfsp->fsp_name;
296 struct files_struct *fsp = NULL;
297 char dot[] = ".";
298 struct smb_filename smb_dot = {
299 .base_name = dot,
300 .flags = smb_dname->flags,
301 .twrp = smb_dname->twrp,
303 NTSTATUS status;
305 status = create_internal_dirfsp(conn, smb_dname, &fsp);
306 if (!NT_STATUS_IS_OK(status)) {
307 return status;
311 * Pointless for opening ".", but you never know...
313 open_flags |= O_NOFOLLOW;
315 status = fd_openat(dirfsp, &smb_dot, fsp, open_flags, 0);
316 if (!NT_STATUS_IS_OK(status)) {
317 DBG_INFO("fd_openat(\"%s\", \".\") failed: %s\n",
318 fsp_str_dbg(dirfsp),
319 nt_errstr(status));
320 file_free(NULL, fsp);
321 return status;
324 fsp->fsp_name->st = smb_dname->st;
325 fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
326 *_fsp = fsp;
327 return NT_STATUS_OK;
331 * The "link" in the name doesn't imply link in the filesystem
332 * sense. It's a object that "links" together an fsp and an smb_fname
333 * and the link allocated as talloc child of an fsp.
335 * The link is created for fsps that openat_pathref_fsp() returns in
336 * smb_fname->fsp. When this fsp is freed by file_free() by some caller
337 * somewhere, the destructor fsp_smb_fname_link_destructor() on the link object
338 * will use the link to reset the reference in smb_fname->fsp that is about to
339 * go away.
341 * This prevents smb_fname_internal_fsp_destructor() from seeing dangling fsp
342 * pointers.
345 struct fsp_smb_fname_link {
346 struct fsp_smb_fname_link **smb_fname_link;
347 struct files_struct **smb_fname_fsp;
350 static int fsp_smb_fname_link_destructor(struct fsp_smb_fname_link *link)
352 if (link->smb_fname_link == NULL) {
353 return 0;
356 *link->smb_fname_link = NULL;
357 *link->smb_fname_fsp = NULL;
358 return 0;
361 static NTSTATUS fsp_smb_fname_link(struct files_struct *fsp,
362 struct fsp_smb_fname_link **smb_fname_link,
363 struct files_struct **smb_fname_fsp)
365 struct fsp_smb_fname_link *link = NULL;
367 SMB_ASSERT(*smb_fname_link == NULL);
368 SMB_ASSERT(*smb_fname_fsp == NULL);
370 link = talloc_zero(fsp, struct fsp_smb_fname_link);
371 if (link == NULL) {
372 return NT_STATUS_NO_MEMORY;
375 link->smb_fname_link = smb_fname_link;
376 link->smb_fname_fsp = smb_fname_fsp;
377 *smb_fname_link = link;
378 *smb_fname_fsp = fsp;
380 talloc_set_destructor(link, fsp_smb_fname_link_destructor);
381 return NT_STATUS_OK;
385 * Free a link, carefully avoiding to trigger the link destructor
387 static void destroy_fsp_smb_fname_link(struct fsp_smb_fname_link **_link)
389 struct fsp_smb_fname_link *link = *_link;
391 if (link == NULL) {
392 return;
394 talloc_set_destructor(link, NULL);
395 TALLOC_FREE(link);
396 *_link = NULL;
400 * Talloc destructor set on an smb_fname set by openat_pathref_fsp() used to
401 * close the embedded smb_fname->fsp.
403 static int smb_fname_fsp_destructor(struct smb_filename *smb_fname)
405 struct files_struct *fsp = smb_fname->fsp;
406 NTSTATUS status;
407 int saved_errno = errno;
409 destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
411 if (fsp == NULL) {
412 errno = saved_errno;
413 return 0;
416 if (fsp_is_alternate_stream(fsp)) {
417 struct files_struct *tmp_base_fsp = fsp->base_fsp;
419 fsp_set_base_fsp(fsp, NULL);
421 status = fd_close(tmp_base_fsp);
422 if (!NT_STATUS_IS_OK(status)) {
423 DBG_ERR("Closing fd for fsp [%s] failed: %s. "
424 "Please check your filesystem!!!\n",
425 fsp_str_dbg(fsp), nt_errstr(status));
427 file_free(NULL, tmp_base_fsp);
430 status = fd_close(fsp);
431 if (!NT_STATUS_IS_OK(status)) {
432 DBG_ERR("Closing fd for fsp [%s] failed: %s. "
433 "Please check your filesystem!!!\n",
434 fsp_str_dbg(fsp), nt_errstr(status));
436 file_free(NULL, fsp);
437 smb_fname->fsp = NULL;
439 errno = saved_errno;
440 return 0;
443 static NTSTATUS openat_pathref_fullname(
444 const struct files_struct *dirfsp,
445 struct smb_filename **full_fname,
446 struct smb_filename *smb_fname)
448 struct connection_struct *conn = dirfsp->conn;
449 struct files_struct *fsp = NULL;
450 NTSTATUS status;
452 DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(smb_fname));
454 SMB_ASSERT(smb_fname->fsp == NULL);
456 status = fsp_new(conn, conn, &fsp);
457 if (!NT_STATUS_IS_OK(status)) {
458 return status;
461 GetTimeOfDay(&fsp->open_time);
462 fsp_set_gen_id(fsp);
463 ZERO_STRUCT(conn->sconn->fsp_fi_cache);
465 fsp->fsp_flags.is_pathref = true;
467 status = fsp_attach_smb_fname(fsp, full_fname);
468 if (!NT_STATUS_IS_OK(status)) {
469 goto fail;
472 status = fd_openat(
473 dirfsp, smb_fname, fsp, O_RDONLY|O_NONBLOCK, 0);
474 if (!NT_STATUS_IS_OK(status)) {
476 smb_fname->st = fsp->fsp_name->st;
478 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) ||
479 NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
480 NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK))
483 * streams_xattr return NT_STATUS_NOT_FOUND for
484 * opens of not yet existing streams.
486 * ELOOP maps to NT_STATUS_OBJECT_PATH_NOT_FOUND
487 * and this will result from a open request from
488 * a POSIX client on a symlink.
490 * NT_STATUS_OBJECT_NAME_NOT_FOUND is the simple
491 * ENOENT case.
493 * NT_STATUS_STOPPED_ON_SYMLINK is returned when trying
494 * to open a symlink, our callers are not interested in
495 * this.
497 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
499 goto fail;
503 * fd_openat() has done an FSTAT on the handle
504 * so update the smb_fname stat info with "truth".
505 * from the handle.
507 smb_fname->st = fsp->fsp_name->st;
509 fsp->fsp_flags.is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
511 fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
513 status = fsp_smb_fname_link(fsp,
514 &smb_fname->fsp_link,
515 &smb_fname->fsp);
516 if (!NT_STATUS_IS_OK(status)) {
517 goto fail;
520 DBG_DEBUG("fsp [%s]: OK\n", fsp_str_dbg(fsp));
522 talloc_set_destructor(smb_fname, smb_fname_fsp_destructor);
523 return NT_STATUS_OK;
525 fail:
526 DBG_DEBUG("Opening pathref for [%s] failed: %s\n",
527 smb_fname_str_dbg(smb_fname),
528 nt_errstr(status));
530 fd_close(fsp);
531 file_free(NULL, fsp);
532 return status;
536 * Open an internal O_PATH based fsp for smb_fname. If O_PATH is not
537 * available, open O_RDONLY as root. Both is done in fd_open() ->
538 * non_widelink_open(), triggered by setting fsp->fsp_flags.is_pathref to
539 * true.
541 NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp,
542 struct smb_filename *smb_fname)
544 connection_struct *conn = dirfsp->conn;
545 struct smb_filename *full_fname = NULL;
546 struct smb_filename *base_fname = NULL;
547 NTSTATUS status;
549 DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(smb_fname));
551 if (smb_fname->fsp != NULL) {
552 /* We already have one for this name. */
553 DBG_DEBUG("smb_fname [%s] already has a pathref fsp.\n",
554 smb_fname_str_dbg(smb_fname));
555 return NT_STATUS_OK;
558 if (!(conn->fs_capabilities & FILE_NAMED_STREAMS) ||
559 !is_named_stream(smb_fname)) {
561 * openat_pathref_fullname() will make "full_fname" a
562 * talloc child of the smb_fname->fsp. Don't use
563 * talloc_tos() to allocate it to avoid making the
564 * talloc stackframe pool long-lived.
566 full_fname = full_path_from_dirfsp_atname(
567 conn,
568 dirfsp,
569 smb_fname);
570 if (full_fname == NULL) {
571 status = NT_STATUS_NO_MEMORY;
572 goto fail;
574 status = openat_pathref_fullname(
575 dirfsp, &full_fname, smb_fname);
576 TALLOC_FREE(full_fname);
577 return status;
581 * stream open
583 base_fname = cp_smb_filename_nostream(conn, smb_fname);
584 if (base_fname == NULL) {
585 return NT_STATUS_NO_MEMORY;
588 full_fname = full_path_from_dirfsp_atname(
589 conn, /* no talloc_tos(), see comment above */
590 dirfsp,
591 base_fname);
592 if (full_fname == NULL) {
593 status = NT_STATUS_NO_MEMORY;
594 goto fail;
597 status = openat_pathref_fullname(
598 dirfsp, &full_fname, base_fname);
599 TALLOC_FREE(full_fname);
600 if (!NT_STATUS_IS_OK(status)) {
601 DBG_DEBUG("openat_pathref_nostream failed: %s\n",
602 nt_errstr(status));
603 goto fail;
606 status = open_stream_pathref_fsp(&base_fname->fsp, smb_fname);
607 if (!NT_STATUS_IS_OK(status)) {
608 DBG_DEBUG("open_stream_pathref_fsp failed: %s\n",
609 nt_errstr(status));
610 goto fail;
613 smb_fname_fsp_unlink(base_fname);
614 fail:
615 TALLOC_FREE(base_fname);
616 return status;
620 * Open a stream given an already opened base_fsp. Avoid
621 * non_widelink_open: This is only valid for the case where we have a
622 * valid non-cwd_fsp dirfsp that we can pass to SMB_VFS_OPENAT()
624 NTSTATUS open_stream_pathref_fsp(
625 struct files_struct **_base_fsp,
626 struct smb_filename *smb_fname)
628 struct files_struct *base_fsp = *_base_fsp;
629 connection_struct *conn = base_fsp->conn;
630 struct smb_filename *base_fname = base_fsp->fsp_name;
631 struct smb_filename *full_fname = NULL;
632 struct files_struct *fsp = NULL;
633 int ret, fd;
634 NTSTATUS status;
636 SMB_ASSERT(smb_fname->fsp == NULL);
637 SMB_ASSERT(is_named_stream(smb_fname));
639 status = fsp_new(conn, conn, &fsp);
640 if (!NT_STATUS_IS_OK(status)) {
641 return status;
644 GetTimeOfDay(&fsp->open_time);
645 fsp_set_gen_id(fsp);
646 ZERO_STRUCT(conn->sconn->fsp_fi_cache);
648 fsp->fsp_flags.is_pathref = true;
650 full_fname = synthetic_smb_fname(
651 fsp,
652 base_fname->base_name,
653 smb_fname->stream_name,
654 &smb_fname->st,
655 smb_fname->twrp,
656 smb_fname->flags);
657 if (full_fname == NULL) {
658 status = NT_STATUS_NO_MEMORY;
659 goto fail;
662 status = fsp_attach_smb_fname(fsp, &full_fname);
663 if (!NT_STATUS_IS_OK(status)) {
664 goto fail;
667 fsp_set_base_fsp(fsp, *_base_fsp);
670 * non_widelink_open() not required: See the asserts above,
671 * this will only open the stream relative to.
674 fd = SMB_VFS_OPENAT(
675 conn,
676 NULL, /* stream open is relative to fsp->base_fsp */
677 smb_fname,
678 fsp,
679 O_RDONLY|O_NONBLOCK,
681 fsp_set_fd(fsp, fd);
683 if (fd == -1) {
684 status = map_nt_error_from_unix(errno);
685 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
686 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
688 goto fail;
691 ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
692 if (ret != 0) {
693 status = map_nt_error_from_unix(errno);
694 goto fail;
697 smb_fname->st = fsp->fsp_name->st;
699 fsp->fsp_flags.is_directory = false; /* streams can't be a directory */
700 fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
702 status = fsp_smb_fname_link(fsp,
703 &smb_fname->fsp_link,
704 &smb_fname->fsp);
705 if (!NT_STATUS_IS_OK(status)) {
706 goto fail;
709 DBG_DEBUG("fsp [%s]: OK\n", fsp_str_dbg(fsp));
711 talloc_set_destructor(smb_fname, smb_fname_fsp_destructor);
712 return NT_STATUS_OK;
714 fail:
715 if (fsp != NULL) {
716 fsp_set_base_fsp(fsp, NULL);
717 fd_close(fsp);
718 file_free(NULL, fsp);
720 return status;
723 void smb_fname_fsp_unlink(struct smb_filename *smb_fname)
725 talloc_set_destructor(smb_fname, NULL);
726 smb_fname->fsp = NULL;
727 destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
731 * Move any existing embedded fsp refs from the src name to the
732 * destination. It's safe to call this on src smb_fname's that have no embedded
733 * pathref fsp.
735 NTSTATUS move_smb_fname_fsp_link(struct smb_filename *smb_fname_dst,
736 struct smb_filename *smb_fname_src)
738 NTSTATUS status;
741 * The target should always not be linked yet!
743 SMB_ASSERT(smb_fname_dst->fsp == NULL);
744 SMB_ASSERT(smb_fname_dst->fsp_link == NULL);
746 if (smb_fname_src->fsp == NULL) {
747 return NT_STATUS_OK;
750 status = fsp_smb_fname_link(smb_fname_src->fsp,
751 &smb_fname_dst->fsp_link,
752 &smb_fname_dst->fsp);
753 if (!NT_STATUS_IS_OK(status)) {
754 return status;
757 talloc_set_destructor(smb_fname_dst, smb_fname_fsp_destructor);
759 smb_fname_fsp_unlink(smb_fname_src);
761 return NT_STATUS_OK;
765 * Create an smb_fname and open smb_fname->fsp pathref
767 NTSTATUS synthetic_pathref(TALLOC_CTX *mem_ctx,
768 struct files_struct *dirfsp,
769 const char *base_name,
770 const char *stream_name,
771 const SMB_STRUCT_STAT *psbuf,
772 NTTIME twrp,
773 uint32_t flags,
774 struct smb_filename **_smb_fname)
776 struct smb_filename *smb_fname = NULL;
777 NTSTATUS status;
779 smb_fname = synthetic_smb_fname(mem_ctx,
780 base_name,
781 stream_name,
782 psbuf,
783 twrp,
784 flags);
785 if (smb_fname == NULL) {
786 return NT_STATUS_NO_MEMORY;
789 status = openat_pathref_fsp(dirfsp, smb_fname);
790 if (!NT_STATUS_IS_OK(status)) {
791 DBG_ERR("opening [%s] failed\n",
792 smb_fname_str_dbg(smb_fname));
793 TALLOC_FREE(smb_fname);
794 return status;
797 *_smb_fname = smb_fname;
798 return NT_STATUS_OK;
801 static int atname_destructor(struct smb_filename *smb_fname)
803 destroy_fsp_smb_fname_link(&smb_fname->fsp_link);
804 return 0;
808 * Turn a path into a parent pathref and atname
810 * This returns the parent pathref in _parent and the name relative to it. If
811 * smb_fname was a pathref (ie smb_fname->fsp != NULL), then _atname will be a
812 * pathref as well, ie _atname->fsp will point at the same fsp as
813 * smb_fname->fsp.
815 NTSTATUS parent_pathref(TALLOC_CTX *mem_ctx,
816 struct files_struct *dirfsp,
817 const struct smb_filename *smb_fname,
818 struct smb_filename **_parent,
819 struct smb_filename **_atname)
821 struct smb_filename *parent = NULL;
822 struct smb_filename *atname = NULL;
823 NTSTATUS status;
825 status = SMB_VFS_PARENT_PATHNAME(dirfsp->conn,
826 mem_ctx,
827 smb_fname,
828 &parent,
829 &atname);
830 if (!NT_STATUS_IS_OK(status)) {
831 return status;
835 * We know that the parent name must
836 * exist, and the name has been canonicalized
837 * even if this was a POSIX pathname.
838 * Ensure that we follow symlinks for
839 * the parent. See the torture test
840 * POSIX-SYMLINK-PARENT for details.
842 parent->flags &= ~SMB_FILENAME_POSIX_PATH;
844 status = openat_pathref_fsp(dirfsp, parent);
845 if (!NT_STATUS_IS_OK(status)) {
846 TALLOC_FREE(parent);
847 return status;
850 if (smb_fname->fsp != NULL) {
851 status = fsp_smb_fname_link(smb_fname->fsp,
852 &atname->fsp_link,
853 &atname->fsp);
854 if (!NT_STATUS_IS_OK(status)) {
855 TALLOC_FREE(parent);
856 return status;
858 talloc_set_destructor(atname, atname_destructor);
860 *_parent = parent;
861 *_atname = atname;
862 return NT_STATUS_OK;
865 static bool close_file_in_loop(struct files_struct *fsp)
867 if (fsp_is_alternate_stream(fsp)) {
869 * This is a stream, it can't be a base
871 SMB_ASSERT(fsp->stream_fsp == NULL);
872 SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
875 * Remove the base<->stream link so that
876 * close_file_free() does not close fsp->base_fsp as
877 * well. This would destroy walking the linked list of
878 * fsps.
880 fsp->base_fsp->stream_fsp = NULL;
881 fsp->base_fsp = NULL;
883 close_file_free(NULL, &fsp, SHUTDOWN_CLOSE);
884 return NULL;
887 if (fsp->stream_fsp != NULL) {
889 * This is the base of a stream.
891 SMB_ASSERT(fsp->stream_fsp->base_fsp == fsp);
894 * Remove the base<->stream link. This will make fsp
895 * look like a normal fsp for the next round.
897 fsp->stream_fsp->base_fsp = NULL;
898 fsp->stream_fsp = NULL;
901 * Have us called back a second time. In the second
902 * round, "fsp" now looks like a normal fsp.
904 return false;
907 close_file_free(NULL, &fsp, SHUTDOWN_CLOSE);
908 return true;
911 /****************************************************************************
912 Close all open files for a connection.
913 ****************************************************************************/
915 struct file_close_conn_state {
916 struct connection_struct *conn;
917 bool fsp_left_behind;
920 static struct files_struct *file_close_conn_fn(
921 struct files_struct *fsp,
922 void *private_data)
924 struct file_close_conn_state *state = private_data;
925 bool did_close;
927 if (fsp->conn != state->conn) {
928 return NULL;
931 if (fsp->op != NULL && fsp->op->global->durable) {
933 * A tree disconnect closes a durable handle
935 fsp->op->global->durable = false;
938 did_close = close_file_in_loop(fsp);
939 if (!did_close) {
940 state->fsp_left_behind = true;
943 return NULL;
946 void file_close_conn(connection_struct *conn)
948 struct file_close_conn_state state = { .conn = conn };
950 files_forall(conn->sconn, file_close_conn_fn, &state);
952 if (state.fsp_left_behind) {
953 state.fsp_left_behind = false;
954 files_forall(conn->sconn, file_close_conn_fn, &state);
955 SMB_ASSERT(!state.fsp_left_behind);
959 /****************************************************************************
960 Initialise file structures.
961 ****************************************************************************/
963 static int files_max_open_fds;
965 bool file_init_global(void)
967 int request_max = lp_max_open_files();
968 int real_lim;
969 int real_max;
971 if (files_max_open_fds != 0) {
972 return true;
976 * Set the max_open files to be the requested
977 * max plus a fudgefactor to allow for the extra
978 * fd's we need such as log files etc...
980 real_lim = set_maxfiles(request_max + MAX_OPEN_FUDGEFACTOR);
982 real_max = real_lim - MAX_OPEN_FUDGEFACTOR;
984 if (real_max + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536) {
985 real_max = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
988 if (real_max != request_max) {
989 DEBUG(1, ("file_init_global: Information only: requested %d "
990 "open files, %d are available.\n",
991 request_max, real_max));
994 SMB_ASSERT(real_max > 100);
996 files_max_open_fds = real_max;
997 return true;
1000 bool file_init(struct smbd_server_connection *sconn)
1002 bool ok;
1004 ok = file_init_global();
1005 if (!ok) {
1006 return false;
1009 sconn->real_max_open_files = files_max_open_fds;
1011 return true;
1014 /****************************************************************************
1015 Close files open by a specified vuid.
1016 ****************************************************************************/
1018 struct file_close_user_state {
1019 uint64_t vuid;
1020 bool fsp_left_behind;
1023 static struct files_struct *file_close_user_fn(
1024 struct files_struct *fsp,
1025 void *private_data)
1027 struct file_close_user_state *state = private_data;
1028 bool did_close;
1030 if (fsp->vuid != state->vuid) {
1031 return NULL;
1034 did_close = close_file_in_loop(fsp);
1035 if (!did_close) {
1036 state->fsp_left_behind = true;
1039 return NULL;
1042 void file_close_user(struct smbd_server_connection *sconn, uint64_t vuid)
1044 struct file_close_user_state state = { .vuid = vuid };
1046 files_forall(sconn, file_close_user_fn, &state);
1048 if (state.fsp_left_behind) {
1049 state.fsp_left_behind = false;
1050 files_forall(sconn, file_close_user_fn, &state);
1051 SMB_ASSERT(!state.fsp_left_behind);
1056 * Walk the files table until "fn" returns non-NULL
1059 struct files_struct *files_forall(
1060 struct smbd_server_connection *sconn,
1061 struct files_struct *(*fn)(struct files_struct *fsp,
1062 void *private_data),
1063 void *private_data)
1065 struct files_struct *fsp, *next;
1067 for (fsp = sconn->files; fsp; fsp = next) {
1068 struct files_struct *ret;
1069 next = fsp->next;
1070 ret = fn(fsp, private_data);
1071 if (ret != NULL) {
1072 return ret;
1075 return NULL;
1078 /****************************************************************************
1079 Find a fsp given a file descriptor.
1080 ****************************************************************************/
1082 files_struct *file_find_fd(struct smbd_server_connection *sconn, int fd)
1084 int count=0;
1085 files_struct *fsp;
1087 for (fsp=sconn->files; fsp; fsp=fsp->next,count++) {
1088 if (fsp_get_pathref_fd(fsp) == fd) {
1089 if (count > 10) {
1090 DLIST_PROMOTE(sconn->files, fsp);
1092 return fsp;
1096 return NULL;
1099 /****************************************************************************
1100 Find a fsp given a device, inode and file_id.
1101 ****************************************************************************/
1103 files_struct *file_find_dif(struct smbd_server_connection *sconn,
1104 struct file_id id, unsigned long gen_id)
1106 int count=0;
1107 files_struct *fsp;
1109 if (gen_id == 0) {
1110 return NULL;
1113 for (fsp = sconn->files; fsp; fsp = fsp->next,count++) {
1115 * We can have a fsp->fh->fd == -1 here as it could be a stat
1116 * open.
1118 if (!file_id_equal(&fsp->file_id, &id)) {
1119 continue;
1121 if (!fsp->fsp_flags.is_fsa) {
1122 continue;
1124 if (fh_get_gen_id(fsp->fh) != gen_id) {
1125 continue;
1127 if (count > 10) {
1128 DLIST_PROMOTE(sconn->files, fsp);
1130 /* Paranoia check. */
1131 if ((fsp_get_pathref_fd(fsp) == -1) &&
1132 (fsp->oplock_type != NO_OPLOCK &&
1133 fsp->oplock_type != LEASE_OPLOCK))
1135 struct file_id_buf idbuf;
1137 DBG_ERR("file %s file_id = "
1138 "%s, gen = %u oplock_type = %u is a "
1139 "stat open with oplock type !\n",
1140 fsp_str_dbg(fsp),
1141 file_id_str_buf(fsp->file_id, &idbuf),
1142 (unsigned int)fh_get_gen_id(fsp->fh),
1143 (unsigned int)fsp->oplock_type);
1144 smb_panic("file_find_dif");
1146 return fsp;
1149 return NULL;
1152 /****************************************************************************
1153 Find the first fsp given a device and inode.
1154 We use a singleton cache here to speed up searching from getfilepathinfo
1155 calls.
1156 ****************************************************************************/
1158 files_struct *file_find_di_first(struct smbd_server_connection *sconn,
1159 struct file_id id,
1160 bool need_fsa)
1162 files_struct *fsp;
1164 if (file_id_equal(&sconn->fsp_fi_cache.id, &id)) {
1165 /* Positive or negative cache hit. */
1166 return sconn->fsp_fi_cache.fsp;
1169 sconn->fsp_fi_cache.id = id;
1171 for (fsp=sconn->files;fsp;fsp=fsp->next) {
1172 if (need_fsa && !fsp->fsp_flags.is_fsa) {
1173 continue;
1175 if (file_id_equal(&fsp->file_id, &id)) {
1176 /* Setup positive cache. */
1177 sconn->fsp_fi_cache.fsp = fsp;
1178 return fsp;
1182 /* Setup negative cache. */
1183 sconn->fsp_fi_cache.fsp = NULL;
1184 return NULL;
1187 /****************************************************************************
1188 Find the next fsp having the same device and inode.
1189 ****************************************************************************/
1191 files_struct *file_find_di_next(files_struct *start_fsp,
1192 bool need_fsa)
1194 files_struct *fsp;
1196 for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
1197 if (need_fsa && !fsp->fsp_flags.is_fsa) {
1198 continue;
1200 if (file_id_equal(&fsp->file_id, &start_fsp->file_id)) {
1201 return fsp;
1205 return NULL;
1208 struct files_struct *file_find_one_fsp_from_lease_key(
1209 struct smbd_server_connection *sconn,
1210 const struct smb2_lease_key *lease_key)
1212 struct files_struct *fsp;
1214 for (fsp = sconn->files; fsp; fsp=fsp->next) {
1215 if ((fsp->lease != NULL) &&
1216 (fsp->lease->lease.lease_key.data[0] ==
1217 lease_key->data[0]) &&
1218 (fsp->lease->lease.lease_key.data[1] ==
1219 lease_key->data[1])) {
1220 return fsp;
1223 return NULL;
1226 /****************************************************************************
1227 Find any fsp open with a pathname below that of an already open path.
1228 ****************************************************************************/
1230 bool file_find_subpath(files_struct *dir_fsp)
1232 files_struct *fsp;
1233 size_t dlen;
1234 char *d_fullname = NULL;
1236 d_fullname = talloc_asprintf(talloc_tos(), "%s/%s",
1237 dir_fsp->conn->connectpath,
1238 dir_fsp->fsp_name->base_name);
1240 if (!d_fullname) {
1241 return false;
1244 dlen = strlen(d_fullname);
1246 for (fsp=dir_fsp->conn->sconn->files; fsp; fsp=fsp->next) {
1247 char *d1_fullname;
1249 if (fsp == dir_fsp) {
1250 continue;
1253 d1_fullname = talloc_asprintf(talloc_tos(),
1254 "%s/%s",
1255 fsp->conn->connectpath,
1256 fsp->fsp_name->base_name);
1259 * If the open file has a path that is a longer
1260 * component, then it's a subpath.
1262 if (strnequal(d_fullname, d1_fullname, dlen) &&
1263 (d1_fullname[dlen] == '/')) {
1264 TALLOC_FREE(d1_fullname);
1265 TALLOC_FREE(d_fullname);
1266 return true;
1268 TALLOC_FREE(d1_fullname);
1271 TALLOC_FREE(d_fullname);
1272 return false;
1275 /****************************************************************************
1276 Free up a fsp.
1277 ****************************************************************************/
1279 static void fsp_free(files_struct *fsp)
1281 struct smbd_server_connection *sconn = fsp->conn->sconn;
1283 if (fsp == sconn->fsp_fi_cache.fsp) {
1284 ZERO_STRUCT(sconn->fsp_fi_cache);
1287 DLIST_REMOVE(sconn->files, fsp);
1288 SMB_ASSERT(sconn->num_files > 0);
1289 sconn->num_files--;
1291 TALLOC_FREE(fsp->fake_file_handle);
1293 if (fh_get_refcount(fsp->fh) == 1) {
1294 TALLOC_FREE(fsp->fh);
1295 } else {
1296 size_t new_refcount = fh_get_refcount(fsp->fh) - 1;
1297 fh_set_refcount(fsp->fh, new_refcount);
1300 if (fsp->lease != NULL) {
1301 if (fsp->lease->ref_count == 1) {
1302 TALLOC_FREE(fsp->lease);
1303 } else {
1304 fsp->lease->ref_count--;
1308 fsp->conn->num_files_open--;
1310 if (fsp->fsp_name != NULL &&
1311 fsp->fsp_name->fsp_link != NULL)
1314 * Free fsp_link of fsp->fsp_name. To do this in the correct
1315 * talloc destructor order we have to do it here. The
1316 * talloc_free() of the link should set the fsp pointer to NULL.
1318 TALLOC_FREE(fsp->fsp_name->fsp_link);
1319 SMB_ASSERT(fsp->fsp_name->fsp == NULL);
1322 /* this is paranoia, just in case someone tries to reuse the
1323 information */
1324 ZERO_STRUCTP(fsp);
1326 /* fsp->fsp_name is a talloc child and is free'd automatically. */
1327 TALLOC_FREE(fsp);
1331 * Rundown of all smb-related sub-structures of an fsp
1333 void fsp_unbind_smb(struct smb_request *req, files_struct *fsp)
1335 if (fsp == fsp->conn->cwd_fsp) {
1336 return;
1339 if (fsp->notify) {
1340 size_t len = fsp_fullbasepath(fsp, NULL, 0);
1341 char fullpath[len+1];
1343 fsp_fullbasepath(fsp, fullpath, sizeof(fullpath));
1346 * Avoid /. at the end of the path name. notify can't
1347 * deal with it.
1349 if (len > 1 && fullpath[len-1] == '.' &&
1350 fullpath[len-2] == '/') {
1351 fullpath[len-2] = '\0';
1354 notify_remove(fsp->conn->sconn->notify_ctx, fsp, fullpath);
1355 TALLOC_FREE(fsp->notify);
1358 /* Ensure this event will never fire. */
1359 TALLOC_FREE(fsp->update_write_time_event);
1361 if (fsp->op != NULL) {
1362 fsp->op->compat = NULL;
1364 TALLOC_FREE(fsp->op);
1366 if ((req != NULL) && (fsp == req->chain_fsp)) {
1367 req->chain_fsp = NULL;
1371 * Clear all possible chained fsp
1372 * pointers in the SMB2 request queue.
1374 remove_smb2_chained_fsp(fsp);
1377 void file_free(struct smb_request *req, files_struct *fsp)
1379 struct smbd_server_connection *sconn = fsp->conn->sconn;
1380 uint64_t fnum = fsp->fnum;
1382 fsp_unbind_smb(req, fsp);
1384 /* Drop all remaining extensions. */
1385 vfs_remove_all_fsp_extensions(fsp);
1387 fsp_free(fsp);
1389 DBG_INFO("freed files structure %"PRIu64" (%zu used)\n",
1390 fnum,
1391 sconn->num_files);
1394 /****************************************************************************
1395 Get an fsp from a packet given a 16 bit fnum.
1396 ****************************************************************************/
1398 files_struct *file_fsp(struct smb_request *req, uint16_t fid)
1400 struct smbXsrv_open *op;
1401 NTSTATUS status;
1402 NTTIME now = 0;
1403 files_struct *fsp;
1405 if (req == NULL) {
1407 * We should never get here. req==NULL could in theory
1408 * only happen from internal opens with a non-zero
1409 * root_dir_fid. Internal opens just don't do that, at
1410 * least they are not supposed to do so. And if they
1411 * start to do so, they better fake up a smb_request
1412 * from which we get the right smbd_server_conn. While
1413 * this should never happen, let's return NULL here.
1415 return NULL;
1418 if (req->chain_fsp != NULL) {
1419 if (req->chain_fsp->fsp_flags.closing) {
1420 return NULL;
1422 return req->chain_fsp;
1425 if (req->xconn == NULL) {
1426 return NULL;
1429 now = timeval_to_nttime(&req->request_time);
1431 status = smb1srv_open_lookup(req->xconn,
1432 fid, now, &op);
1433 if (!NT_STATUS_IS_OK(status)) {
1434 return NULL;
1437 fsp = op->compat;
1438 if (fsp == NULL) {
1439 return NULL;
1442 if (fsp->fsp_flags.closing) {
1443 return NULL;
1446 req->chain_fsp = fsp;
1447 return fsp;
1450 struct files_struct *file_fsp_get(struct smbd_smb2_request *smb2req,
1451 uint64_t persistent_id,
1452 uint64_t volatile_id)
1454 struct smbXsrv_open *op;
1455 NTSTATUS status;
1456 NTTIME now = 0;
1457 struct files_struct *fsp;
1459 now = timeval_to_nttime(&smb2req->request_time);
1461 status = smb2srv_open_lookup(smb2req->xconn,
1462 persistent_id, volatile_id,
1463 now, &op);
1464 if (!NT_STATUS_IS_OK(status)) {
1465 return NULL;
1468 fsp = op->compat;
1469 if (fsp == NULL) {
1470 return NULL;
1473 if (smb2req->tcon == NULL) {
1474 return NULL;
1477 if (smb2req->tcon->compat != fsp->conn) {
1478 return NULL;
1481 if (smb2req->session == NULL) {
1482 return NULL;
1485 if (smb2req->session->global->session_wire_id != fsp->vuid) {
1486 return NULL;
1489 if (fsp->fsp_flags.closing) {
1490 return NULL;
1493 return fsp;
1496 struct files_struct *file_fsp_smb2(struct smbd_smb2_request *smb2req,
1497 uint64_t persistent_id,
1498 uint64_t volatile_id)
1500 struct files_struct *fsp;
1502 if (smb2req->compat_chain_fsp != NULL) {
1503 if (smb2req->compat_chain_fsp->fsp_flags.closing) {
1504 return NULL;
1506 return smb2req->compat_chain_fsp;
1509 fsp = file_fsp_get(smb2req, persistent_id, volatile_id);
1510 if (fsp == NULL) {
1511 return NULL;
1514 smb2req->compat_chain_fsp = fsp;
1515 return fsp;
1518 /****************************************************************************
1519 Duplicate the file handle part for a DOS or FCB open.
1520 ****************************************************************************/
1522 NTSTATUS dup_file_fsp(
1523 files_struct *from,
1524 uint32_t access_mask,
1525 files_struct *to)
1527 size_t new_refcount;
1529 /* this can never happen for print files */
1530 SMB_ASSERT(from->print_file == NULL);
1532 TALLOC_FREE(to->fh);
1534 to->fh = from->fh;
1535 new_refcount = fh_get_refcount(to->fh) + 1;
1536 fh_set_refcount(to->fh, new_refcount);
1538 to->file_id = from->file_id;
1539 to->initial_allocation_size = from->initial_allocation_size;
1540 to->file_pid = from->file_pid;
1541 to->vuid = from->vuid;
1542 to->open_time = from->open_time;
1543 to->access_mask = access_mask;
1544 to->oplock_type = from->oplock_type;
1545 to->fsp_flags.can_lock = from->fsp_flags.can_lock;
1546 to->fsp_flags.can_read = ((access_mask & FILE_READ_DATA) != 0);
1547 to->fsp_flags.can_write =
1548 CAN_WRITE(from->conn) &&
1549 ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
1550 to->fsp_flags.modified = from->fsp_flags.modified;
1551 to->fsp_flags.is_directory = from->fsp_flags.is_directory;
1552 to->fsp_flags.aio_write_behind = from->fsp_flags.aio_write_behind;
1553 to->fsp_flags.is_fsa = from->fsp_flags.is_fsa;
1554 to->fsp_flags.is_pathref = from->fsp_flags.is_pathref;
1555 to->fsp_flags.have_proc_fds = from->fsp_flags.have_proc_fds;
1556 to->fsp_flags.is_dirfsp = from->fsp_flags.is_dirfsp;
1558 return fsp_set_smb_fname(to, from->fsp_name);
1562 * Return a jenkins hash of a pathname on a connection.
1565 NTSTATUS file_name_hash(connection_struct *conn,
1566 const char *name, uint32_t *p_name_hash)
1568 char tmpbuf[PATH_MAX];
1569 char *fullpath, *to_free;
1570 ssize_t len;
1571 TDB_DATA key;
1573 /* Set the hash of the full pathname. */
1575 if (name[0] == '/') {
1576 strlcpy(tmpbuf, name, sizeof(tmpbuf));
1577 fullpath = tmpbuf;
1578 len = strlen(fullpath);
1579 to_free = NULL;
1580 } else {
1581 len = full_path_tos(conn->connectpath,
1582 name,
1583 tmpbuf,
1584 sizeof(tmpbuf),
1585 &fullpath,
1586 &to_free);
1588 if (len == -1) {
1589 return NT_STATUS_NO_MEMORY;
1591 key = (TDB_DATA) { .dptr = (uint8_t *)fullpath, .dsize = len+1 };
1592 *p_name_hash = tdb_jenkins_hash(&key);
1594 DEBUG(10,("file_name_hash: %s hash 0x%x\n",
1595 fullpath,
1596 (unsigned int)*p_name_hash ));
1598 TALLOC_FREE(to_free);
1599 return NT_STATUS_OK;
1602 static NTSTATUS fsp_attach_smb_fname(struct files_struct *fsp,
1603 struct smb_filename **_smb_fname)
1605 struct smb_filename *smb_fname_new = talloc_move(fsp, _smb_fname);
1606 const char *name_str = NULL;
1607 uint32_t name_hash = 0;
1608 NTSTATUS status;
1610 name_str = smb_fname_str_dbg(smb_fname_new);
1611 if (name_str == NULL) {
1612 return NT_STATUS_NO_MEMORY;
1615 status = file_name_hash(fsp->conn,
1616 name_str,
1617 &name_hash);
1618 if (!NT_STATUS_IS_OK(status)) {
1619 return status;
1622 status = fsp_smb_fname_link(fsp,
1623 &smb_fname_new->fsp_link,
1624 &smb_fname_new->fsp);
1625 if (!NT_STATUS_IS_OK(status)) {
1626 return status;
1629 fsp->name_hash = name_hash;
1630 fsp->fsp_name = smb_fname_new;
1631 *_smb_fname = NULL;
1632 return NT_STATUS_OK;
1636 * The only way that the fsp->fsp_name field should ever be set.
1638 NTSTATUS fsp_set_smb_fname(struct files_struct *fsp,
1639 const struct smb_filename *smb_fname_in)
1641 struct smb_filename *smb_fname_old = fsp->fsp_name;
1642 struct smb_filename *smb_fname_new = NULL;
1643 NTSTATUS status;
1645 smb_fname_new = cp_smb_filename(fsp, smb_fname_in);
1646 if (smb_fname_new == NULL) {
1647 return NT_STATUS_NO_MEMORY;
1650 status = fsp_attach_smb_fname(fsp, &smb_fname_new);
1651 if (!NT_STATUS_IS_OK(status)) {
1652 TALLOC_FREE(smb_fname_new);
1653 return status;
1656 if (smb_fname_old != NULL) {
1657 smb_fname_fsp_unlink(smb_fname_old);
1658 TALLOC_FREE(smb_fname_old);
1661 return NT_STATUS_OK;
1664 size_t fsp_fullbasepath(struct files_struct *fsp, char *buf, size_t buflen)
1666 int len = 0;
1667 char tmp_buf[1] = {'\0'};
1670 * Don't pass NULL buffer to snprintf (to satisfy static checker)
1671 * Some callers will call this function with NULL for buf and
1672 * 0 for buflen in order to get length of fullbasepath (without
1673 * needing to allocate or write to buf)
1675 if (buf == NULL) {
1676 buf = tmp_buf;
1677 SMB_ASSERT(buflen==0);
1680 len = snprintf(buf, buflen, "%s/%s", fsp->conn->connectpath,
1681 fsp->fsp_name->base_name);
1682 SMB_ASSERT(len>0);
1684 return len;
1687 void fsp_set_base_fsp(struct files_struct *fsp, struct files_struct *base_fsp)
1689 SMB_ASSERT(fsp->stream_fsp == NULL);
1690 if (base_fsp != NULL) {
1691 SMB_ASSERT(base_fsp->base_fsp == NULL);
1692 SMB_ASSERT(base_fsp->stream_fsp == NULL);
1695 if (fsp->base_fsp != NULL) {
1696 SMB_ASSERT(fsp->base_fsp->stream_fsp == fsp);
1697 fsp->base_fsp->stream_fsp = NULL;
1700 fsp->base_fsp = base_fsp;
1701 if (fsp->base_fsp != NULL) {
1702 fsp->base_fsp->stream_fsp = fsp;
1706 bool fsp_is_alternate_stream(const struct files_struct *fsp)
1708 return (fsp->base_fsp != NULL);
1711 struct files_struct *metadata_fsp(struct files_struct *fsp)
1713 if (fsp_is_alternate_stream(fsp)) {
1714 return fsp->base_fsp;
1716 return fsp;