2 * Store streams in a separate subdirectory
4 * Copyright (C) Volker Lendecke, 2007
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/>.
21 #include "smbd/smbd.h"
22 #include "system/filesys.h"
25 #define DBGC_CLASS DBGC_VFS
28 * Excerpt from a mail from tridge:
30 * Volker, what I'm thinking of is this:
31 * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream1
32 * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream2
34 * where XX/YY is a 2 level hash based on the fsid/inode. "aaaa.bbbb"
35 * is the fsid/inode. "namedstreamX" is a file named after the stream
39 static uint32_t hash_fn(DATA_BLOB key)
41 uint32_t value; /* Used to compute the hash value. */
42 uint32_t i; /* Used to cycle through random values. */
44 /* Set the initial value from the key size. */
45 for (value = 0x238F13AF * key.length, i=0; i < key.length; i++)
46 value = (value + (key.data[i] << (i*5 % 24)));
48 return (1103515243 * value + 12345);
52 * With the hashing scheme based on the inode we need to protect against
53 * streams showing up on files with re-used inodes. This can happen if we
54 * create a stream directory from within Samba, and a local process or NFS
55 * client deletes the file without deleting the streams directory. When the
56 * inode is re-used and the stream directory is still around, the streams in
57 * there would be show up as belonging to the new file.
59 * There are several workarounds for this, probably the easiest one is on
60 * systems which have a true birthtime stat element: When the file has a later
61 * birthtime than the streams directory, then we have to recreate the
64 * The other workaround is to somehow mark the file as generated by Samba with
65 * something that a NFS client would not do. The closest one is a special
66 * xattr value being set. On systems which do not support xattrs, it might be
67 * an option to put in a special ACL entry for a non-existing group.
70 static bool file_is_valid(vfs_handle_struct *handle,
71 const struct smb_filename *smb_fname)
75 DEBUG(10, ("file_is_valid (%s) called\n", smb_fname->base_name));
77 if (SMB_VFS_GETXATTR(handle->conn, smb_fname, SAMBA_XATTR_MARKER,
78 &buf, sizeof(buf)) != sizeof(buf)) {
79 DEBUG(10, ("GETXATTR failed: %s\n", strerror(errno)));
84 DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
91 static bool mark_file_valid(vfs_handle_struct *handle,
92 const struct smb_filename *smb_fname)
97 DEBUG(10, ("marking file %s as valid\n", smb_fname->base_name));
99 ret = SMB_VFS_SETXATTR(handle->conn, smb_fname, SAMBA_XATTR_MARKER,
100 &buf, sizeof(buf), 0);
103 DEBUG(10, ("SETXATTR failed: %s\n", strerror(errno)));
111 * Given an smb_filename, determine the stream directory using the file's
114 static char *stream_dir(vfs_handle_struct *handle,
115 const struct smb_filename *smb_fname,
116 const SMB_STRUCT_STAT *base_sbuf, bool create_it)
119 struct smb_filename *smb_fname_hash = NULL;
121 SMB_STRUCT_STAT base_sbuf_tmp;
122 uint8_t first, second;
128 char *rootdir = NULL;
129 struct smb_filename *rootdir_fname = NULL;
130 struct smb_filename *tmp_fname = NULL;
132 check_valid = lp_parm_bool(SNUM(handle->conn),
133 "streams_depot", "check_valid", true);
135 tmp = talloc_asprintf(talloc_tos(), "%s/.streams",
136 handle->conn->connectpath);
143 rootdir = lp_parm_talloc_string(talloc_tos(),
144 SNUM(handle->conn), "streams_depot", "directory",
146 if (rootdir == NULL) {
151 rootdir_fname = synthetic_smb_fname(talloc_tos(),
156 if (rootdir_fname == NULL) {
161 /* Stat the base file if it hasn't already been done. */
162 if (base_sbuf == NULL) {
163 struct smb_filename *smb_fname_base;
165 smb_fname_base = synthetic_smb_fname(
167 smb_fname->base_name,
171 if (smb_fname_base == NULL) {
175 if (SMB_VFS_NEXT_STAT(handle, smb_fname_base) == -1) {
176 TALLOC_FREE(smb_fname_base);
179 base_sbuf_tmp = smb_fname_base->st;
180 TALLOC_FREE(smb_fname_base);
182 base_sbuf_tmp = *base_sbuf;
185 id = SMB_VFS_FILE_ID_CREATE(handle->conn, &base_sbuf_tmp);
187 push_file_id_16((char *)id_buf, &id);
189 hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf)));
192 second = (hash >> 8) & 0xff;
194 id_hex = hex_encode_talloc(talloc_tos(), id_buf, sizeof(id_buf));
196 if (id_hex == NULL) {
201 result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir,
202 first, second, id_hex);
206 if (result == NULL) {
211 smb_fname_hash = synthetic_smb_fname(talloc_tos(),
216 if (smb_fname_hash == NULL) {
221 if (SMB_VFS_NEXT_STAT(handle, smb_fname_hash) == 0) {
222 struct smb_filename *smb_fname_new = NULL;
226 if (!S_ISDIR(smb_fname_hash->st.st_ex_mode)) {
232 file_is_valid(handle, smb_fname)) {
237 * Someone has recreated a file under an existing inode
238 * without deleting the streams directory.
239 * Move it away or remove if streams_depot:delete_lost is set.
243 delete_lost = lp_parm_bool(SNUM(handle->conn), "streams_depot",
244 "delete_lost", false);
247 DEBUG(3, ("Someone has recreated a file under an "
248 "existing inode. Removing: %s\n",
249 smb_fname_hash->base_name));
250 recursive_rmdir(talloc_tos(), handle->conn,
252 SMB_VFS_NEXT_RMDIR(handle, smb_fname_hash);
254 newname = talloc_asprintf(talloc_tos(), "lost-%lu",
256 DEBUG(3, ("Someone has recreated a file under an "
257 "existing inode. Renaming: %s to: %s\n",
258 smb_fname_hash->base_name,
260 if (newname == NULL) {
265 smb_fname_new = synthetic_smb_fname(
271 TALLOC_FREE(newname);
272 if (smb_fname_new == NULL) {
277 if (SMB_VFS_NEXT_RENAME(handle, smb_fname_hash,
278 smb_fname_new) == -1) {
279 TALLOC_FREE(smb_fname_new);
280 if ((errno == EEXIST) || (errno == ENOTEMPTY)) {
286 TALLOC_FREE(smb_fname_new);
295 if ((SMB_VFS_NEXT_MKDIR(handle, rootdir_fname, 0755) != 0)
296 && (errno != EEXIST)) {
300 tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
306 tmp_fname = synthetic_smb_fname(talloc_tos(),
311 if (tmp_fname == NULL) {
316 if ((SMB_VFS_NEXT_MKDIR(handle, tmp_fname, 0755) != 0)
317 && (errno != EEXIST)) {
322 TALLOC_FREE(tmp_fname);
324 tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
331 tmp_fname = synthetic_smb_fname(talloc_tos(),
336 if (tmp_fname == NULL) {
341 if ((SMB_VFS_NEXT_MKDIR(handle, tmp_fname, 0755) != 0)
342 && (errno != EEXIST)) {
347 TALLOC_FREE(tmp_fname);
349 /* smb_fname_hash is the struct smb_filename version of 'result' */
350 if ((SMB_VFS_NEXT_MKDIR(handle, smb_fname_hash, 0755) != 0)
351 && (errno != EEXIST)) {
355 if (check_valid && !mark_file_valid(handle, smb_fname)) {
359 TALLOC_FREE(rootdir_fname);
360 TALLOC_FREE(rootdir);
361 TALLOC_FREE(tmp_fname);
362 TALLOC_FREE(smb_fname_hash);
366 TALLOC_FREE(rootdir_fname);
367 TALLOC_FREE(rootdir);
368 TALLOC_FREE(tmp_fname);
369 TALLOC_FREE(smb_fname_hash);
374 * Given a stream name, populate smb_fname_out with the actual location of the
377 static NTSTATUS stream_smb_fname(vfs_handle_struct *handle,
378 const struct smb_filename *smb_fname,
379 struct smb_filename **smb_fname_out,
382 char *dirname, *stream_fname;
386 *smb_fname_out = NULL;
388 stype = strchr_m(smb_fname->stream_name + 1, ':');
391 if (strcasecmp_m(stype, ":$DATA") != 0) {
392 return NT_STATUS_INVALID_PARAMETER;
396 dirname = stream_dir(handle, smb_fname, NULL, create_dir);
398 if (dirname == NULL) {
399 status = map_nt_error_from_unix(errno);
403 stream_fname = talloc_asprintf(talloc_tos(), "%s/%s", dirname,
404 smb_fname->stream_name);
406 if (stream_fname == NULL) {
407 status = NT_STATUS_NO_MEMORY;
412 /* Append an explicit stream type if one wasn't specified. */
413 stream_fname = talloc_asprintf(talloc_tos(), "%s:$DATA",
415 if (stream_fname == NULL) {
416 status = NT_STATUS_NO_MEMORY;
420 /* Normalize the stream type to upercase. */
421 if (!strupper_m(strrchr_m(stream_fname, ':') + 1)) {
422 status = NT_STATUS_INVALID_PARAMETER;
427 DEBUG(10, ("stream filename = %s\n", stream_fname));
429 /* Create an smb_filename with stream_name == NULL. */
430 *smb_fname_out = synthetic_smb_fname(talloc_tos(),
435 if (*smb_fname_out == NULL) {
436 return NT_STATUS_NO_MEMORY;
442 DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
443 TALLOC_FREE(*smb_fname_out);
447 static NTSTATUS walk_streams(vfs_handle_struct *handle,
448 struct smb_filename *smb_fname_base,
450 bool (*fn)(const char *dirname,
456 struct smb_filename *dir_smb_fname = NULL;
457 DIR *dirhandle = NULL;
458 const char *dirent = NULL;
459 char *talloced = NULL;
461 dirname = stream_dir(handle, smb_fname_base, &smb_fname_base->st,
464 if (dirname == NULL) {
465 if (errno == ENOENT) {
471 return map_nt_error_from_unix(errno);
474 DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
476 dir_smb_fname = synthetic_smb_fname(talloc_tos(),
480 smb_fname_base->flags);
481 if (dir_smb_fname == NULL) {
482 TALLOC_FREE(dirname);
483 return NT_STATUS_NO_MEMORY;
486 dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dir_smb_fname, NULL, 0);
488 TALLOC_FREE(dir_smb_fname);
490 if (dirhandle == NULL) {
491 TALLOC_FREE(dirname);
492 return map_nt_error_from_unix(errno);
495 while ((dirent = vfs_readdirname(handle->conn, dirhandle, NULL,
496 &talloced)) != NULL) {
498 if (ISDOT(dirent) || ISDOTDOT(dirent)) {
499 TALLOC_FREE(talloced);
503 DEBUG(10, ("walk_streams: dirent=%s\n", dirent));
505 if (!fn(dirname, dirent, private_data)) {
506 TALLOC_FREE(talloced);
509 TALLOC_FREE(talloced);
512 SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle);
514 if (pdirname != NULL) {
518 TALLOC_FREE(dirname);
525 * Helper to stat/lstat the base file of an smb_fname. This will actually
526 * fills in the stat struct in smb_filename.
528 static int streams_depot_stat_base(vfs_handle_struct *handle,
529 struct smb_filename *smb_fname,
532 char *tmp_stream_name;
535 tmp_stream_name = smb_fname->stream_name;
536 smb_fname->stream_name = NULL;
538 result = SMB_VFS_NEXT_STAT(handle, smb_fname);
540 result = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
542 smb_fname->stream_name = tmp_stream_name;
546 static int streams_depot_stat(vfs_handle_struct *handle,
547 struct smb_filename *smb_fname)
549 struct smb_filename *smb_fname_stream = NULL;
553 DEBUG(10, ("streams_depot_stat called for [%s]\n",
554 smb_fname_str_dbg(smb_fname)));
556 if (!is_ntfs_stream_smb_fname(smb_fname)) {
557 return SMB_VFS_NEXT_STAT(handle, smb_fname);
560 /* If the default stream is requested, just stat the base file. */
561 if (is_ntfs_default_stream_smb_fname(smb_fname)) {
562 return streams_depot_stat_base(handle, smb_fname, true);
565 /* Stat the actual stream now. */
566 status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
568 if (!NT_STATUS_IS_OK(status)) {
570 errno = map_errno_from_nt_status(status);
574 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_stream);
576 /* Update the original smb_fname with the stat info. */
577 smb_fname->st = smb_fname_stream->st;
579 TALLOC_FREE(smb_fname_stream);
585 static int streams_depot_lstat(vfs_handle_struct *handle,
586 struct smb_filename *smb_fname)
588 struct smb_filename *smb_fname_stream = NULL;
592 DEBUG(10, ("streams_depot_lstat called for [%s]\n",
593 smb_fname_str_dbg(smb_fname)));
595 if (!is_ntfs_stream_smb_fname(smb_fname)) {
596 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
599 /* If the default stream is requested, just stat the base file. */
600 if (is_ntfs_default_stream_smb_fname(smb_fname)) {
601 return streams_depot_stat_base(handle, smb_fname, false);
604 /* Stat the actual stream now. */
605 status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
607 if (!NT_STATUS_IS_OK(status)) {
609 errno = map_errno_from_nt_status(status);
613 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_stream);
616 TALLOC_FREE(smb_fname_stream);
620 static int streams_depot_open(vfs_handle_struct *handle,
621 struct smb_filename *smb_fname,
622 files_struct *fsp, int flags, mode_t mode)
624 struct smb_filename *smb_fname_stream = NULL;
625 struct smb_filename *smb_fname_base = NULL;
629 if (!is_ntfs_stream_smb_fname(smb_fname)) {
630 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
633 /* If the default stream is requested, just open the base file. */
634 if (is_ntfs_default_stream_smb_fname(smb_fname)) {
635 char *tmp_stream_name;
637 tmp_stream_name = smb_fname->stream_name;
638 smb_fname->stream_name = NULL;
639 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
640 smb_fname->stream_name = tmp_stream_name;
645 /* Ensure the base file still exists. */
646 smb_fname_base = synthetic_smb_fname(talloc_tos(),
647 smb_fname->base_name,
651 if (smb_fname_base == NULL) {
657 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
662 /* Determine the stream name, and then open it. */
663 status = stream_smb_fname(handle, smb_fname, &smb_fname_stream, true);
664 if (!NT_STATUS_IS_OK(status)) {
666 errno = map_errno_from_nt_status(status);
670 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname_stream, fsp, flags, mode);
673 TALLOC_FREE(smb_fname_stream);
674 TALLOC_FREE(smb_fname_base);
678 static int streams_depot_unlink(vfs_handle_struct *handle,
679 const struct smb_filename *smb_fname)
681 struct smb_filename *smb_fname_base = NULL;
684 DEBUG(10, ("streams_depot_unlink called for %s\n",
685 smb_fname_str_dbg(smb_fname)));
687 /* If there is a valid stream, just unlink the stream and return. */
688 if (is_ntfs_stream_smb_fname(smb_fname) &&
689 !is_ntfs_default_stream_smb_fname(smb_fname)) {
690 struct smb_filename *smb_fname_stream = NULL;
693 status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
695 if (!NT_STATUS_IS_OK(status)) {
696 errno = map_errno_from_nt_status(status);
700 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_stream);
702 TALLOC_FREE(smb_fname_stream);
707 * We potentially need to delete the per-inode streams directory
710 smb_fname_base = synthetic_smb_fname(talloc_tos(),
711 smb_fname->base_name,
715 if (smb_fname_base == NULL) {
720 if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
721 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
723 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
727 TALLOC_FREE(smb_fname_base);
732 * We know the unlink should succeed as the ACL
733 * check is already done in the caller. Remove the
734 * file *after* the streams.
737 char *dirname = stream_dir(handle, smb_fname_base,
738 &smb_fname_base->st, false);
740 if (dirname != NULL) {
741 struct smb_filename *smb_fname_dir =
742 synthetic_smb_fname(talloc_tos(),
747 if (smb_fname_dir == NULL) {
748 TALLOC_FREE(smb_fname_base);
749 TALLOC_FREE(dirname);
753 SMB_VFS_NEXT_RMDIR(handle, smb_fname_dir);
754 TALLOC_FREE(smb_fname_dir);
756 TALLOC_FREE(dirname);
759 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
760 TALLOC_FREE(smb_fname_base);
764 static int streams_depot_rmdir(vfs_handle_struct *handle,
765 const struct smb_filename *smb_fname)
767 struct smb_filename *smb_fname_base = NULL;
770 DEBUG(10, ("streams_depot_rmdir called for %s\n",
771 smb_fname->base_name));
774 * We potentially need to delete the per-inode streams directory
777 smb_fname_base = synthetic_smb_fname(talloc_tos(),
778 smb_fname->base_name,
782 if (smb_fname_base == NULL) {
787 if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
788 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
790 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
794 TALLOC_FREE(smb_fname_base);
799 * We know the rmdir should succeed as the ACL
800 * check is already done in the caller. Remove the
801 * directory *after* the streams.
804 char *dirname = stream_dir(handle, smb_fname_base,
805 &smb_fname_base->st, false);
807 if (dirname != NULL) {
808 struct smb_filename *smb_fname_dir =
809 synthetic_smb_fname(talloc_tos(),
814 if (smb_fname_dir == NULL) {
815 TALLOC_FREE(smb_fname_base);
816 TALLOC_FREE(dirname);
820 SMB_VFS_NEXT_RMDIR(handle, smb_fname_dir);
821 TALLOC_FREE(smb_fname_dir);
823 TALLOC_FREE(dirname);
826 ret = SMB_VFS_NEXT_RMDIR(handle, smb_fname_base);
827 TALLOC_FREE(smb_fname_base);
831 static int streams_depot_rename(vfs_handle_struct *handle,
832 const struct smb_filename *smb_fname_src,
833 const struct smb_filename *smb_fname_dst)
835 struct smb_filename *smb_fname_src_stream = NULL;
836 struct smb_filename *smb_fname_dst_stream = NULL;
837 bool src_is_stream, dst_is_stream;
841 DEBUG(10, ("streams_depot_rename called for %s => %s\n",
842 smb_fname_str_dbg(smb_fname_src),
843 smb_fname_str_dbg(smb_fname_dst)));
845 src_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
846 dst_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
848 if (!src_is_stream && !dst_is_stream) {
849 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
853 /* for now don't allow renames from or to the default stream */
854 if (is_ntfs_default_stream_smb_fname(smb_fname_src) ||
855 is_ntfs_default_stream_smb_fname(smb_fname_dst)) {
860 status = stream_smb_fname(handle, smb_fname_src, &smb_fname_src_stream,
862 if (!NT_STATUS_IS_OK(status)) {
863 errno = map_errno_from_nt_status(status);
867 status = stream_smb_fname(handle, smb_fname_dst,
868 &smb_fname_dst_stream, false);
869 if (!NT_STATUS_IS_OK(status)) {
870 errno = map_errno_from_nt_status(status);
874 ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src_stream,
875 smb_fname_dst_stream);
878 TALLOC_FREE(smb_fname_src_stream);
879 TALLOC_FREE(smb_fname_dst_stream);
883 static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
884 struct stream_struct **streams,
885 const char *name, off_t size,
888 struct stream_struct *tmp;
890 tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
896 tmp[*num_streams].name = talloc_strdup(tmp, name);
897 if (tmp[*num_streams].name == NULL) {
901 tmp[*num_streams].size = size;
902 tmp[*num_streams].alloc_size = alloc_size;
909 struct streaminfo_state {
911 vfs_handle_struct *handle;
912 unsigned int num_streams;
913 struct stream_struct *streams;
917 static bool collect_one_stream(const char *dirname,
921 struct streaminfo_state *state =
922 (struct streaminfo_state *)private_data;
923 struct smb_filename *smb_fname = NULL;
927 sname = talloc_asprintf(talloc_tos(), "%s/%s", dirname, dirent);
929 state->status = NT_STATUS_NO_MEMORY;
934 smb_fname = synthetic_smb_fname(talloc_tos(), sname, NULL, NULL, 0);
935 if (smb_fname == NULL) {
936 state->status = NT_STATUS_NO_MEMORY;
941 if (SMB_VFS_NEXT_STAT(state->handle, smb_fname) == -1) {
942 DEBUG(10, ("Could not stat %s: %s\n", sname,
948 if (!add_one_stream(state->mem_ctx,
949 &state->num_streams, &state->streams,
950 dirent, smb_fname->st.st_ex_size,
951 SMB_VFS_GET_ALLOC_SIZE(state->handle->conn, NULL,
953 state->status = NT_STATUS_NO_MEMORY;
961 TALLOC_FREE(smb_fname);
965 static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
966 struct files_struct *fsp,
967 const struct smb_filename *smb_fname,
969 unsigned int *pnum_streams,
970 struct stream_struct **pstreams)
972 struct smb_filename *smb_fname_base = NULL;
975 struct streaminfo_state state;
977 smb_fname_base = synthetic_smb_fname(talloc_tos(),
978 smb_fname->base_name,
982 if (smb_fname_base == NULL) {
983 return NT_STATUS_NO_MEMORY;
986 if ((fsp != NULL) && (fsp->fh->fd != -1)) {
987 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &smb_fname_base->st);
990 if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
991 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
993 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
998 status = map_nt_error_from_unix(errno);
1002 state.streams = *pstreams;
1003 state.num_streams = *pnum_streams;
1004 state.mem_ctx = mem_ctx;
1005 state.handle = handle;
1006 state.status = NT_STATUS_OK;
1008 if (S_ISLNK(smb_fname_base->st.st_ex_mode)) {
1010 * Currently we do't have SMB_VFS_LLISTXATTR
1011 * inside the VFS which means there's no way
1012 * to cope with a symlink when lp_posix_pathnames().
1013 * returns true. For now ignore links.
1014 * FIXME - by adding SMB_VFS_LLISTXATTR. JRA.
1016 status = NT_STATUS_OK;
1018 status = walk_streams(handle, smb_fname_base, NULL, collect_one_stream,
1022 if (!NT_STATUS_IS_OK(status)) {
1023 TALLOC_FREE(state.streams);
1027 if (!NT_STATUS_IS_OK(state.status)) {
1028 TALLOC_FREE(state.streams);
1029 status = state.status;
1033 *pnum_streams = state.num_streams;
1034 *pstreams = state.streams;
1035 status = SMB_VFS_NEXT_STREAMINFO(handle,
1043 TALLOC_FREE(smb_fname_base);
1047 static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle,
1048 enum timestamp_set_resolution *p_ts_res)
1050 return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS;
1053 static struct vfs_fn_pointers vfs_streams_depot_fns = {
1054 .fs_capabilities_fn = streams_depot_fs_capabilities,
1055 .open_fn = streams_depot_open,
1056 .stat_fn = streams_depot_stat,
1057 .lstat_fn = streams_depot_lstat,
1058 .unlink_fn = streams_depot_unlink,
1059 .rmdir_fn = streams_depot_rmdir,
1060 .rename_fn = streams_depot_rename,
1061 .streaminfo_fn = streams_depot_streaminfo,
1064 NTSTATUS vfs_streams_depot_init(TALLOC_CTX *);
1065 NTSTATUS vfs_streams_depot_init(TALLOC_CTX *ctx)
1067 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
1068 &vfs_streams_depot_fns);