s4:selftest: explicitly set NSS/RESOLV_WAPPER_* in wait_for_start
[Samba.git] / source3 / modules / vfs_streams_depot.c
blob31625b347118040a4a73974a81310f39627532da
1 /*
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/>.
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "system/filesys.h"
24 #undef DBGC_CLASS
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
36 * name.
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
62 * directory.
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)
73 char buf;
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)));
80 return false;
83 if (buf != '1') {
84 DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
85 return false;
88 return true;
91 static bool mark_file_valid(vfs_handle_struct *handle,
92 const struct smb_filename *smb_fname)
94 char buf = '1';
95 int ret;
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);
102 if (ret == -1) {
103 DEBUG(10, ("SETXATTR failed: %s\n", strerror(errno)));
104 return false;
107 return true;
111 * Given an smb_filename, determine the stream directory using the file's
112 * base_name.
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)
118 uint32_t hash;
119 struct smb_filename *smb_fname_hash = NULL;
120 char *result = NULL;
121 SMB_STRUCT_STAT base_sbuf_tmp;
122 uint8_t first, second;
123 char *tmp;
124 char *id_hex;
125 struct file_id id;
126 uint8_t id_buf[16];
127 bool check_valid;
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);
138 if (tmp == NULL) {
139 errno = ENOMEM;
140 goto fail;
143 rootdir = lp_parm_talloc_string(talloc_tos(),
144 SNUM(handle->conn), "streams_depot", "directory",
145 tmp);
146 if (rootdir == NULL) {
147 errno = ENOMEM;
148 goto fail;
151 rootdir_fname = synthetic_smb_fname(talloc_tos(),
152 rootdir,
153 NULL,
154 NULL,
155 smb_fname->flags);
156 if (rootdir_fname == NULL) {
157 errno = ENOMEM;
158 goto fail;
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(
166 talloc_tos(),
167 smb_fname->base_name,
168 NULL,
169 NULL,
170 smb_fname->flags);
171 if (smb_fname_base == NULL) {
172 errno = ENOMEM;
173 goto fail;
175 if (SMB_VFS_NEXT_STAT(handle, smb_fname_base) == -1) {
176 TALLOC_FREE(smb_fname_base);
177 goto fail;
179 base_sbuf_tmp = smb_fname_base->st;
180 TALLOC_FREE(smb_fname_base);
181 } else {
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)));
191 first = hash & 0xff;
192 second = (hash >> 8) & 0xff;
194 id_hex = hex_encode_talloc(talloc_tos(), id_buf, sizeof(id_buf));
196 if (id_hex == NULL) {
197 errno = ENOMEM;
198 goto fail;
201 result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir,
202 first, second, id_hex);
204 TALLOC_FREE(id_hex);
206 if (result == NULL) {
207 errno = ENOMEM;
208 return NULL;
211 smb_fname_hash = synthetic_smb_fname(talloc_tos(),
212 result,
213 NULL,
214 NULL,
215 smb_fname->flags);
216 if (smb_fname_hash == NULL) {
217 errno = ENOMEM;
218 goto fail;
221 if (SMB_VFS_NEXT_STAT(handle, smb_fname_hash) == 0) {
222 struct smb_filename *smb_fname_new = NULL;
223 char *newname;
224 bool delete_lost;
226 if (!S_ISDIR(smb_fname_hash->st.st_ex_mode)) {
227 errno = EINVAL;
228 goto fail;
231 if (!check_valid ||
232 file_is_valid(handle, smb_fname)) {
233 return result;
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.
242 again:
243 delete_lost = lp_parm_bool(SNUM(handle->conn), "streams_depot",
244 "delete_lost", false);
246 if (delete_lost) {
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,
251 smb_fname_hash);
252 SMB_VFS_NEXT_RMDIR(handle, smb_fname_hash);
253 } else {
254 newname = talloc_asprintf(talloc_tos(), "lost-%lu",
255 random());
256 DEBUG(3, ("Someone has recreated a file under an "
257 "existing inode. Renaming: %s to: %s\n",
258 smb_fname_hash->base_name,
259 newname));
260 if (newname == NULL) {
261 errno = ENOMEM;
262 goto fail;
265 smb_fname_new = synthetic_smb_fname(
266 talloc_tos(),
267 newname,
268 NULL,
269 NULL,
270 smb_fname->flags);
271 TALLOC_FREE(newname);
272 if (smb_fname_new == NULL) {
273 errno = ENOMEM;
274 goto fail;
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)) {
281 goto again;
283 goto fail;
286 TALLOC_FREE(smb_fname_new);
290 if (!create_it) {
291 errno = ENOENT;
292 goto fail;
295 if ((SMB_VFS_NEXT_MKDIR(handle, rootdir_fname, 0755) != 0)
296 && (errno != EEXIST)) {
297 goto fail;
300 tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
301 if (tmp == NULL) {
302 errno = ENOMEM;
303 goto fail;
306 tmp_fname = synthetic_smb_fname(talloc_tos(),
307 tmp,
308 NULL,
309 NULL,
310 smb_fname->flags);
311 if (tmp_fname == NULL) {
312 errno = ENOMEM;
313 goto fail;
316 if ((SMB_VFS_NEXT_MKDIR(handle, tmp_fname, 0755) != 0)
317 && (errno != EEXIST)) {
318 goto fail;
321 TALLOC_FREE(tmp);
322 TALLOC_FREE(tmp_fname);
324 tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
325 second);
326 if (tmp == NULL) {
327 errno = ENOMEM;
328 goto fail;
331 tmp_fname = synthetic_smb_fname(talloc_tos(),
332 tmp,
333 NULL,
334 NULL,
335 smb_fname->flags);
336 if (tmp_fname == NULL) {
337 errno = ENOMEM;
338 goto fail;
341 if ((SMB_VFS_NEXT_MKDIR(handle, tmp_fname, 0755) != 0)
342 && (errno != EEXIST)) {
343 goto fail;
346 TALLOC_FREE(tmp);
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)) {
352 goto fail;
355 if (check_valid && !mark_file_valid(handle, smb_fname)) {
356 goto fail;
359 TALLOC_FREE(rootdir_fname);
360 TALLOC_FREE(rootdir);
361 TALLOC_FREE(tmp_fname);
362 TALLOC_FREE(smb_fname_hash);
363 return result;
365 fail:
366 TALLOC_FREE(rootdir_fname);
367 TALLOC_FREE(rootdir);
368 TALLOC_FREE(tmp_fname);
369 TALLOC_FREE(smb_fname_hash);
370 TALLOC_FREE(result);
371 return NULL;
374 * Given a stream name, populate smb_fname_out with the actual location of the
375 * stream.
377 static NTSTATUS stream_smb_fname(vfs_handle_struct *handle,
378 const struct smb_filename *smb_fname,
379 struct smb_filename **smb_fname_out,
380 bool create_dir)
382 char *dirname, *stream_fname;
383 const char *stype;
384 NTSTATUS status;
386 *smb_fname_out = NULL;
388 stype = strchr_m(smb_fname->stream_name + 1, ':');
390 if (stype) {
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);
400 goto fail;
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;
408 goto fail;
411 if (stype == NULL) {
412 /* Append an explicit stream type if one wasn't specified. */
413 stream_fname = talloc_asprintf(talloc_tos(), "%s:$DATA",
414 stream_fname);
415 if (stream_fname == NULL) {
416 status = NT_STATUS_NO_MEMORY;
417 goto fail;
419 } else {
420 /* Normalize the stream type to upercase. */
421 if (!strupper_m(strrchr_m(stream_fname, ':') + 1)) {
422 status = NT_STATUS_INVALID_PARAMETER;
423 goto fail;
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(),
431 stream_fname,
432 NULL,
433 NULL,
434 smb_fname->flags);
435 if (*smb_fname_out == NULL) {
436 return NT_STATUS_NO_MEMORY;
439 return NT_STATUS_OK;
441 fail:
442 DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
443 TALLOC_FREE(*smb_fname_out);
444 return status;
447 static NTSTATUS walk_streams(vfs_handle_struct *handle,
448 struct smb_filename *smb_fname_base,
449 char **pdirname,
450 bool (*fn)(const char *dirname,
451 const char *dirent,
452 void *private_data),
453 void *private_data)
455 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,
462 false);
464 if (dirname == NULL) {
465 if (errno == ENOENT) {
467 * no stream around
469 return NT_STATUS_OK;
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(),
477 dirname,
478 NULL,
479 NULL,
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);
500 continue;
503 DEBUG(10, ("walk_streams: dirent=%s\n", dirent));
505 if (!fn(dirname, dirent, private_data)) {
506 TALLOC_FREE(talloced);
507 break;
509 TALLOC_FREE(talloced);
512 SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle);
514 if (pdirname != NULL) {
515 *pdirname = dirname;
517 else {
518 TALLOC_FREE(dirname);
521 return NT_STATUS_OK;
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,
530 bool follow_links)
532 char *tmp_stream_name;
533 int result;
535 tmp_stream_name = smb_fname->stream_name;
536 smb_fname->stream_name = NULL;
537 if (follow_links) {
538 result = SMB_VFS_NEXT_STAT(handle, smb_fname);
539 } else {
540 result = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
542 smb_fname->stream_name = tmp_stream_name;
543 return result;
546 static int streams_depot_stat(vfs_handle_struct *handle,
547 struct smb_filename *smb_fname)
549 struct smb_filename *smb_fname_stream = NULL;
550 NTSTATUS status;
551 int ret = -1;
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,
567 false);
568 if (!NT_STATUS_IS_OK(status)) {
569 ret = -1;
570 errno = map_errno_from_nt_status(status);
571 goto done;
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;
578 done:
579 TALLOC_FREE(smb_fname_stream);
580 return ret;
585 static int streams_depot_lstat(vfs_handle_struct *handle,
586 struct smb_filename *smb_fname)
588 struct smb_filename *smb_fname_stream = NULL;
589 NTSTATUS status;
590 int ret = -1;
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,
606 false);
607 if (!NT_STATUS_IS_OK(status)) {
608 ret = -1;
609 errno = map_errno_from_nt_status(status);
610 goto done;
613 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_stream);
615 done:
616 TALLOC_FREE(smb_fname_stream);
617 return ret;
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;
626 NTSTATUS status;
627 int ret = -1;
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;
642 return ret;
645 /* Ensure the base file still exists. */
646 smb_fname_base = synthetic_smb_fname(talloc_tos(),
647 smb_fname->base_name,
648 NULL,
649 NULL,
650 smb_fname->flags);
651 if (smb_fname_base == NULL) {
652 ret = -1;
653 errno = ENOMEM;
654 goto done;
657 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
658 if (ret == -1) {
659 goto done;
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)) {
665 ret = -1;
666 errno = map_errno_from_nt_status(status);
667 goto done;
670 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname_stream, fsp, flags, mode);
672 done:
673 TALLOC_FREE(smb_fname_stream);
674 TALLOC_FREE(smb_fname_base);
675 return ret;
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;
682 int ret = -1;
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;
691 NTSTATUS status;
693 status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
694 false);
695 if (!NT_STATUS_IS_OK(status)) {
696 errno = map_errno_from_nt_status(status);
697 return -1;
700 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_stream);
702 TALLOC_FREE(smb_fname_stream);
703 return ret;
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,
712 NULL,
713 NULL,
714 smb_fname->flags);
715 if (smb_fname_base == NULL) {
716 errno = ENOMEM;
717 return -1;
720 if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
721 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
722 } else {
723 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
726 if (ret == -1) {
727 TALLOC_FREE(smb_fname_base);
728 return -1;
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(),
743 dirname,
744 NULL,
745 NULL,
746 smb_fname->flags);
747 if (smb_fname_dir == NULL) {
748 TALLOC_FREE(smb_fname_base);
749 TALLOC_FREE(dirname);
750 errno = ENOMEM;
751 return -1;
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);
761 return ret;
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;
768 int ret = -1;
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,
779 NULL,
780 NULL,
781 smb_fname->flags);
782 if (smb_fname_base == NULL) {
783 errno = ENOMEM;
784 return -1;
787 if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
788 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
789 } else {
790 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
793 if (ret == -1) {
794 TALLOC_FREE(smb_fname_base);
795 return -1;
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(),
810 dirname,
811 NULL,
812 NULL,
813 smb_fname->flags);
814 if (smb_fname_dir == NULL) {
815 TALLOC_FREE(smb_fname_base);
816 TALLOC_FREE(dirname);
817 errno = ENOMEM;
818 return -1;
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);
828 return ret;
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;
838 NTSTATUS status;
839 int ret = -1;
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,
850 smb_fname_dst);
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)) {
856 errno = ENOSYS;
857 goto done;
860 status = stream_smb_fname(handle, smb_fname_src, &smb_fname_src_stream,
861 false);
862 if (!NT_STATUS_IS_OK(status)) {
863 errno = map_errno_from_nt_status(status);
864 goto done;
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);
871 goto done;
874 ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src_stream,
875 smb_fname_dst_stream);
877 done:
878 TALLOC_FREE(smb_fname_src_stream);
879 TALLOC_FREE(smb_fname_dst_stream);
880 return ret;
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,
886 off_t alloc_size)
888 struct stream_struct *tmp;
890 tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
891 (*num_streams)+1);
892 if (tmp == NULL) {
893 return false;
896 tmp[*num_streams].name = talloc_strdup(tmp, name);
897 if (tmp[*num_streams].name == NULL) {
898 return false;
901 tmp[*num_streams].size = size;
902 tmp[*num_streams].alloc_size = alloc_size;
904 *streams = tmp;
905 *num_streams += 1;
906 return true;
909 struct streaminfo_state {
910 TALLOC_CTX *mem_ctx;
911 vfs_handle_struct *handle;
912 unsigned int num_streams;
913 struct stream_struct *streams;
914 NTSTATUS status;
917 static bool collect_one_stream(const char *dirname,
918 const char *dirent,
919 void *private_data)
921 struct streaminfo_state *state =
922 (struct streaminfo_state *)private_data;
923 struct smb_filename *smb_fname = NULL;
924 char *sname = NULL;
925 bool ret;
927 sname = talloc_asprintf(talloc_tos(), "%s/%s", dirname, dirent);
928 if (sname == NULL) {
929 state->status = NT_STATUS_NO_MEMORY;
930 ret = false;
931 goto out;
934 smb_fname = synthetic_smb_fname(talloc_tos(), sname, NULL, NULL, 0);
935 if (smb_fname == NULL) {
936 state->status = NT_STATUS_NO_MEMORY;
937 ret = false;
938 goto out;
941 if (SMB_VFS_NEXT_STAT(state->handle, smb_fname) == -1) {
942 DEBUG(10, ("Could not stat %s: %s\n", sname,
943 strerror(errno)));
944 ret = true;
945 goto out;
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,
952 &smb_fname->st))) {
953 state->status = NT_STATUS_NO_MEMORY;
954 ret = false;
955 goto out;
958 ret = true;
959 out:
960 TALLOC_FREE(sname);
961 TALLOC_FREE(smb_fname);
962 return ret;
965 static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
966 struct files_struct *fsp,
967 const struct smb_filename *smb_fname,
968 TALLOC_CTX *mem_ctx,
969 unsigned int *pnum_streams,
970 struct stream_struct **pstreams)
972 struct smb_filename *smb_fname_base = NULL;
973 int ret;
974 NTSTATUS status;
975 struct streaminfo_state state;
977 smb_fname_base = synthetic_smb_fname(talloc_tos(),
978 smb_fname->base_name,
979 NULL,
980 NULL,
981 smb_fname->flags);
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);
989 else {
990 if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
991 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
992 } else {
993 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
997 if (ret == -1) {
998 status = map_nt_error_from_unix(errno);
999 goto out;
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;
1017 } else {
1018 status = walk_streams(handle, smb_fname_base, NULL, collect_one_stream,
1019 &state);
1022 if (!NT_STATUS_IS_OK(status)) {
1023 TALLOC_FREE(state.streams);
1024 goto out;
1027 if (!NT_STATUS_IS_OK(state.status)) {
1028 TALLOC_FREE(state.streams);
1029 status = state.status;
1030 goto out;
1033 *pnum_streams = state.num_streams;
1034 *pstreams = state.streams;
1035 status = SMB_VFS_NEXT_STREAMINFO(handle,
1036 fsp,
1037 smb_fname_base,
1038 mem_ctx,
1039 pnum_streams,
1040 pstreams);
1042 out:
1043 TALLOC_FREE(smb_fname_base);
1044 return status;
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 static_decl_vfs;
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);