s3/vfs:stream_depots: Parse substitutions in streams-depot-directory path
[samba.git] / source3 / modules / vfs_streams_depot.c
1 /*
2  * Store streams in a separate subdirectory
3  *
4  * Copyright (C) Volker Lendecke, 2007
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "system/filesys.h"
23
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_VFS
26
27 /*
28  * Excerpt from a mail from tridge:
29  *
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
33  *
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.
37  */
38
39 static uint32_t hash_fn(DATA_BLOB key)
40 {
41         uint32_t value; /* Used to compute the hash value.  */
42         uint32_t i;     /* Used to cycle through random values. */
43
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)));
47
48         return (1103515243 * value + 12345);
49 }
50
51 /*
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.
58  *
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.
63  *
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.
68  */
69
70 static bool file_is_valid(vfs_handle_struct *handle, const char *path)
71 {
72         char buf;
73
74         DEBUG(10, ("file_is_valid (%s) called\n", path));
75
76         if (SMB_VFS_GETXATTR(handle->conn, path, SAMBA_XATTR_MARKER,
77                                   &buf, sizeof(buf)) != sizeof(buf)) {
78                 DEBUG(10, ("GETXATTR failed: %s\n", strerror(errno)));
79                 return false;
80         }
81
82         if (buf != '1') {
83                 DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
84                 return false;
85         }
86
87         return true;
88 }
89
90 static bool mark_file_valid(vfs_handle_struct *handle, const char *path)
91 {
92         char buf = '1';
93         int ret;
94
95         DEBUG(10, ("marking file %s as valid\n", path));
96
97         ret = SMB_VFS_SETXATTR(handle->conn, path, SAMBA_XATTR_MARKER,
98                                     &buf, sizeof(buf), 0);
99
100         if (ret == -1) {
101                 DEBUG(10, ("SETXATTR failed: %s\n", strerror(errno)));
102                 return false;
103         }
104
105         return true;
106 }
107
108 /**
109  * Given an smb_filename, determine the stream directory using the file's
110  * base_name.
111  */
112 static char *stream_dir(vfs_handle_struct *handle,
113                         const struct smb_filename *smb_fname,
114                         const SMB_STRUCT_STAT *base_sbuf, bool create_it)
115 {
116         uint32_t hash;
117         struct smb_filename *smb_fname_hash = NULL;
118         char *result = NULL;
119         SMB_STRUCT_STAT base_sbuf_tmp;
120         uint8_t first, second;
121         char *tmp;
122         char *id_hex;
123         struct file_id id;
124         uint8_t id_buf[16];
125         bool check_valid;
126         char *rootdir = NULL;
127         struct smb_filename *rootdir_fname = NULL;
128         struct smb_filename *tmp_fname = NULL;
129
130         check_valid = lp_parm_bool(SNUM(handle->conn),
131                       "streams_depot", "check_valid", true);
132
133         tmp = talloc_asprintf(talloc_tos(), "%s/.streams", handle->conn->cwd);
134
135         if (tmp == NULL) {
136                 errno = ENOMEM;
137                 goto fail;
138         }
139
140         rootdir = lp_parm_talloc_string(talloc_tos(),
141                 SNUM(handle->conn), "streams_depot", "directory",
142                 tmp);
143         if (rootdir == NULL) {
144                 errno = ENOMEM;
145                 goto fail;
146         }
147
148         rootdir_fname = synthetic_smb_fname(talloc_tos(),
149                                         rootdir,
150                                         NULL,
151                                         NULL);
152         if (rootdir_fname == NULL) {
153                 errno = ENOMEM;
154                 goto fail;
155         }
156
157         /* Stat the base file if it hasn't already been done. */
158         if (base_sbuf == NULL) {
159                 struct smb_filename *smb_fname_base;
160
161                 smb_fname_base = synthetic_smb_fname(
162                         talloc_tos(), smb_fname->base_name, NULL, NULL);
163                 if (smb_fname_base == NULL) {
164                         errno = ENOMEM;
165                         goto fail;
166                 }
167                 if (SMB_VFS_NEXT_STAT(handle, smb_fname_base) == -1) {
168                         TALLOC_FREE(smb_fname_base);
169                         goto fail;
170                 }
171                 base_sbuf_tmp = smb_fname_base->st;
172                 TALLOC_FREE(smb_fname_base);
173         } else {
174                 base_sbuf_tmp = *base_sbuf;
175         }
176
177         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &base_sbuf_tmp);
178
179         push_file_id_16((char *)id_buf, &id);
180
181         hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf)));
182
183         first = hash & 0xff;
184         second = (hash >> 8) & 0xff;
185
186         id_hex = hex_encode_talloc(talloc_tos(), id_buf, sizeof(id_buf));
187
188         if (id_hex == NULL) {
189                 errno = ENOMEM;
190                 goto fail;
191         }
192
193         result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir,
194                                  first, second, id_hex);
195
196         TALLOC_FREE(id_hex);
197
198         if (result == NULL) {
199                 errno = ENOMEM;
200                 return NULL;
201         }
202
203         smb_fname_hash = synthetic_smb_fname(talloc_tos(), result, NULL, NULL);
204         if (smb_fname_hash == NULL) {
205                 errno = ENOMEM;
206                 goto fail;
207         }
208
209         if (SMB_VFS_NEXT_STAT(handle, smb_fname_hash) == 0) {
210                 struct smb_filename *smb_fname_new = NULL;
211                 char *newname;
212                 bool delete_lost;
213
214                 if (!S_ISDIR(smb_fname_hash->st.st_ex_mode)) {
215                         errno = EINVAL;
216                         goto fail;
217                 }
218
219                 if (!check_valid ||
220                     file_is_valid(handle, smb_fname->base_name)) {
221                         return result;
222                 }
223
224                 /*
225                  * Someone has recreated a file under an existing inode
226                  * without deleting the streams directory.
227                  * Move it away or remove if streams_depot:delete_lost is set.
228                  */
229
230         again:
231                 delete_lost = lp_parm_bool(SNUM(handle->conn), "streams_depot",
232                                            "delete_lost", false);
233
234                 if (delete_lost) {
235                         DEBUG(3, ("Someone has recreated a file under an "
236                               "existing inode. Removing: %s\n",
237                               smb_fname_hash->base_name));
238                         recursive_rmdir(talloc_tos(), handle->conn,
239                                         smb_fname_hash);
240                         SMB_VFS_NEXT_RMDIR(handle, smb_fname_hash);
241                 } else {
242                         newname = talloc_asprintf(talloc_tos(), "lost-%lu",
243                                                   random());
244                         DEBUG(3, ("Someone has recreated a file under an "
245                               "existing inode. Renaming: %s to: %s\n",
246                               smb_fname_hash->base_name,
247                               newname));
248                         if (newname == NULL) {
249                                 errno = ENOMEM;
250                                 goto fail;
251                         }
252
253                         smb_fname_new = synthetic_smb_fname(
254                                 talloc_tos(), newname, NULL, NULL);
255                         TALLOC_FREE(newname);
256                         if (smb_fname_new == NULL) {
257                                 errno = ENOMEM;
258                                 goto fail;
259                         }
260
261                         if (SMB_VFS_NEXT_RENAME(handle, smb_fname_hash,
262                                                 smb_fname_new) == -1) {
263                                 TALLOC_FREE(smb_fname_new);
264                                 if ((errno == EEXIST) || (errno == ENOTEMPTY)) {
265                                         goto again;
266                                 }
267                                 goto fail;
268                         }
269
270                         TALLOC_FREE(smb_fname_new);
271                 }
272         }
273
274         if (!create_it) {
275                 errno = ENOENT;
276                 goto fail;
277         }
278
279         if ((SMB_VFS_NEXT_MKDIR(handle, rootdir_fname, 0755) != 0)
280             && (errno != EEXIST)) {
281                 goto fail;
282         }
283
284         tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
285         if (tmp == NULL) {
286                 errno = ENOMEM;
287                 goto fail;
288         }
289
290         tmp_fname = synthetic_smb_fname(talloc_tos(), tmp, NULL, NULL);
291         if (tmp_fname == NULL) {
292                 errno = ENOMEM;
293                 goto fail;
294         }
295
296         if ((SMB_VFS_NEXT_MKDIR(handle, tmp_fname, 0755) != 0)
297             && (errno != EEXIST)) {
298                 goto fail;
299         }
300
301         TALLOC_FREE(tmp);
302         TALLOC_FREE(tmp_fname);
303
304         tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
305                               second);
306         if (tmp == NULL) {
307                 errno = ENOMEM;
308                 goto fail;
309         }
310
311         tmp_fname = synthetic_smb_fname(talloc_tos(), tmp, NULL, NULL);
312         if (tmp_fname == NULL) {
313                 errno = ENOMEM;
314                 goto fail;
315         }
316
317         if ((SMB_VFS_NEXT_MKDIR(handle, tmp_fname, 0755) != 0)
318             && (errno != EEXIST)) {
319                 goto fail;
320         }
321
322         TALLOC_FREE(tmp);
323         TALLOC_FREE(tmp_fname);
324
325         /* smb_fname_hash is the struct smb_filename version of 'result' */
326         if ((SMB_VFS_NEXT_MKDIR(handle, smb_fname_hash, 0755) != 0)
327             && (errno != EEXIST)) {
328                 goto fail;
329         }
330
331         if (check_valid && !mark_file_valid(handle, smb_fname->base_name)) {
332                 goto fail;
333         }
334
335         TALLOC_FREE(rootdir_fname);
336         TALLOC_FREE(rootdir);
337         TALLOC_FREE(tmp_fname);
338         TALLOC_FREE(smb_fname_hash);
339         return result;
340
341  fail:
342         TALLOC_FREE(rootdir_fname);
343         TALLOC_FREE(rootdir);
344         TALLOC_FREE(tmp_fname);
345         TALLOC_FREE(smb_fname_hash);
346         TALLOC_FREE(result);
347         return NULL;
348 }
349 /**
350  * Given a stream name, populate smb_fname_out with the actual location of the
351  * stream.
352  */
353 static NTSTATUS stream_smb_fname(vfs_handle_struct *handle,
354                                  const struct smb_filename *smb_fname,
355                                  struct smb_filename **smb_fname_out,
356                                  bool create_dir)
357 {
358         char *dirname, *stream_fname;
359         const char *stype;
360         NTSTATUS status;
361
362         *smb_fname_out = NULL;
363
364         stype = strchr_m(smb_fname->stream_name + 1, ':');
365
366         if (stype) {
367                 if (strcasecmp_m(stype, ":$DATA") != 0) {
368                         return NT_STATUS_INVALID_PARAMETER;
369                 }
370         }
371
372         dirname = stream_dir(handle, smb_fname, NULL, create_dir);
373
374         if (dirname == NULL) {
375                 status = map_nt_error_from_unix(errno);
376                 goto fail;
377         }
378
379         stream_fname = talloc_asprintf(talloc_tos(), "%s/%s", dirname,
380                                        smb_fname->stream_name);
381
382         if (stream_fname == NULL) {
383                 status = NT_STATUS_NO_MEMORY;
384                 goto fail;
385         }
386
387         if (stype == NULL) {
388                 /* Append an explicit stream type if one wasn't specified. */
389                 stream_fname = talloc_asprintf(talloc_tos(), "%s:$DATA",
390                                                stream_fname);
391                 if (stream_fname == NULL) {
392                         status = NT_STATUS_NO_MEMORY;
393                         goto fail;
394                 }
395         } else {
396                 /* Normalize the stream type to upercase. */
397                 if (!strupper_m(strrchr_m(stream_fname, ':') + 1)) {
398                         status = NT_STATUS_INVALID_PARAMETER;
399                         goto fail;
400                 }
401         }
402
403         DEBUG(10, ("stream filename = %s\n", stream_fname));
404
405         /* Create an smb_filename with stream_name == NULL. */
406         *smb_fname_out = synthetic_smb_fname(
407                 talloc_tos(), stream_fname, NULL, NULL);
408         if (*smb_fname_out == NULL) {
409                 return NT_STATUS_NO_MEMORY;
410         }
411
412         return NT_STATUS_OK;
413
414  fail:
415         DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
416         TALLOC_FREE(*smb_fname_out);
417         return status;
418 }
419
420 static NTSTATUS walk_streams(vfs_handle_struct *handle,
421                              struct smb_filename *smb_fname_base,
422                              char **pdirname,
423                              bool (*fn)(const char *dirname,
424                                         const char *dirent,
425                                         void *private_data),
426                              void *private_data)
427 {
428         char *dirname;
429         struct smb_filename *dir_smb_fname = NULL;
430         DIR *dirhandle = NULL;
431         const char *dirent = NULL;
432         char *talloced = NULL;
433
434         dirname = stream_dir(handle, smb_fname_base, &smb_fname_base->st,
435                              false);
436
437         if (dirname == NULL) {
438                 if (errno == ENOENT) {
439                         /*
440                          * no stream around
441                          */
442                         return NT_STATUS_OK;
443                 }
444                 return map_nt_error_from_unix(errno);
445         }
446
447         DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
448
449         dir_smb_fname = synthetic_smb_fname(talloc_tos(),
450                                         dirname,
451                                         NULL,
452                                         NULL);
453         if (dir_smb_fname == NULL) {
454                 TALLOC_FREE(dirname);
455                 return NT_STATUS_NO_MEMORY;
456         }
457
458         dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dir_smb_fname, NULL, 0);
459
460         TALLOC_FREE(dir_smb_fname);
461
462         if (dirhandle == NULL) {
463                 TALLOC_FREE(dirname);
464                 return map_nt_error_from_unix(errno);
465         }
466
467         while ((dirent = vfs_readdirname(handle->conn, dirhandle, NULL,
468                                          &talloced)) != NULL) {
469
470                 if (ISDOT(dirent) || ISDOTDOT(dirent)) {
471                         TALLOC_FREE(talloced);
472                         continue;
473                 }
474
475                 DEBUG(10, ("walk_streams: dirent=%s\n", dirent));
476
477                 if (!fn(dirname, dirent, private_data)) {
478                         TALLOC_FREE(talloced);
479                         break;
480                 }
481                 TALLOC_FREE(talloced);
482         }
483
484         SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle);
485
486         if (pdirname != NULL) {
487                 *pdirname = dirname;
488         }
489         else {
490                 TALLOC_FREE(dirname);
491         }
492
493         return NT_STATUS_OK;
494 }
495
496 /**
497  * Helper to stat/lstat the base file of an smb_fname. This will actually
498  * fills in the stat struct in smb_filename.
499  */
500 static int streams_depot_stat_base(vfs_handle_struct *handle,
501                                    struct smb_filename *smb_fname,
502                                    bool follow_links)
503 {
504         char *tmp_stream_name;
505         int result;
506
507         tmp_stream_name = smb_fname->stream_name;
508         smb_fname->stream_name = NULL;
509         if (follow_links) {
510                 result = SMB_VFS_NEXT_STAT(handle, smb_fname);
511         } else {
512                 result = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
513         }
514         smb_fname->stream_name = tmp_stream_name;
515         return result;
516 }
517
518 static int streams_depot_stat(vfs_handle_struct *handle,
519                               struct smb_filename *smb_fname)
520 {
521         struct smb_filename *smb_fname_stream = NULL;
522         NTSTATUS status;
523         int ret = -1;
524
525         DEBUG(10, ("streams_depot_stat called for [%s]\n",
526                    smb_fname_str_dbg(smb_fname)));
527
528         if (!is_ntfs_stream_smb_fname(smb_fname)) {
529                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
530         }
531
532         /* If the default stream is requested, just stat the base file. */
533         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
534                 return streams_depot_stat_base(handle, smb_fname, true);
535         }
536
537         /* Stat the actual stream now. */
538         status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
539                                   false);
540         if (!NT_STATUS_IS_OK(status)) {
541                 ret = -1;
542                 errno = map_errno_from_nt_status(status);
543                 goto done;
544         }
545
546         ret = SMB_VFS_NEXT_STAT(handle, smb_fname_stream);
547
548         /* Update the original smb_fname with the stat info. */
549         smb_fname->st = smb_fname_stream->st;
550  done:
551         TALLOC_FREE(smb_fname_stream);
552         return ret;
553 }
554
555
556
557 static int streams_depot_lstat(vfs_handle_struct *handle,
558                                struct smb_filename *smb_fname)
559 {
560         struct smb_filename *smb_fname_stream = NULL;
561         NTSTATUS status;
562         int ret = -1;
563
564         DEBUG(10, ("streams_depot_lstat called for [%s]\n",
565                    smb_fname_str_dbg(smb_fname)));
566
567         if (!is_ntfs_stream_smb_fname(smb_fname)) {
568                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
569         }
570
571         /* If the default stream is requested, just stat the base file. */
572         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
573                 return streams_depot_stat_base(handle, smb_fname, false);
574         }
575
576         /* Stat the actual stream now. */
577         status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
578                                   false);
579         if (!NT_STATUS_IS_OK(status)) {
580                 ret = -1;
581                 errno = map_errno_from_nt_status(status);
582                 goto done;
583         }
584
585         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_stream);
586
587  done:
588         TALLOC_FREE(smb_fname_stream);
589         return ret;
590 }
591
592 static int streams_depot_open(vfs_handle_struct *handle,
593                               struct smb_filename *smb_fname,
594                               files_struct *fsp, int flags, mode_t mode)
595 {
596         struct smb_filename *smb_fname_stream = NULL;
597         struct smb_filename *smb_fname_base = NULL;
598         NTSTATUS status;
599         int ret = -1;
600
601         if (!is_ntfs_stream_smb_fname(smb_fname)) {
602                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
603         }
604
605         /* If the default stream is requested, just open the base file. */
606         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
607                 char *tmp_stream_name;
608
609                 tmp_stream_name = smb_fname->stream_name;
610                 smb_fname->stream_name = NULL;
611                 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
612                 smb_fname->stream_name = tmp_stream_name;
613
614                 return ret;
615         }
616
617         /* Ensure the base file still exists. */
618         smb_fname_base = synthetic_smb_fname(
619                 talloc_tos(), smb_fname->base_name, NULL, NULL);
620         if (smb_fname_base == NULL) {
621                 ret = -1;
622                 errno = ENOMEM;
623                 goto done;
624         }
625
626         ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
627         if (ret == -1) {
628                 goto done;
629         }
630
631         /* Determine the stream name, and then open it. */
632         status = stream_smb_fname(handle, smb_fname, &smb_fname_stream, true);
633         if (!NT_STATUS_IS_OK(status)) {
634                 ret = -1;
635                 errno = map_errno_from_nt_status(status);
636                 goto done;
637         }
638
639         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname_stream, fsp, flags, mode);
640
641  done:
642         TALLOC_FREE(smb_fname_stream);
643         TALLOC_FREE(smb_fname_base);
644         return ret;
645 }
646
647 static int streams_depot_unlink(vfs_handle_struct *handle,
648                                 const struct smb_filename *smb_fname)
649 {
650         struct smb_filename *smb_fname_base = NULL;
651         int ret = -1;
652
653         DEBUG(10, ("streams_depot_unlink called for %s\n",
654                    smb_fname_str_dbg(smb_fname)));
655
656         /* If there is a valid stream, just unlink the stream and return. */
657         if (is_ntfs_stream_smb_fname(smb_fname) &&
658             !is_ntfs_default_stream_smb_fname(smb_fname)) {
659                 struct smb_filename *smb_fname_stream = NULL;
660                 NTSTATUS status;
661
662                 status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
663                                           false);
664                 if (!NT_STATUS_IS_OK(status)) {
665                         errno = map_errno_from_nt_status(status);
666                         return -1;
667                 }
668
669                 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_stream);
670
671                 TALLOC_FREE(smb_fname_stream);
672                 return ret;
673         }
674
675         /*
676          * We potentially need to delete the per-inode streams directory
677          */
678
679         smb_fname_base = synthetic_smb_fname(
680                 talloc_tos(), smb_fname->base_name, NULL, NULL);
681         if (smb_fname_base == NULL) {
682                 errno = ENOMEM;
683                 return -1;
684         }
685
686         if (lp_posix_pathnames()) {
687                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
688         } else {
689                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
690         }
691
692         if (ret == -1) {
693                 TALLOC_FREE(smb_fname_base);
694                 return -1;
695         }
696
697         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
698         if (ret == 0) {
699                 char *dirname = stream_dir(handle, smb_fname_base,
700                                            &smb_fname_base->st, false);
701
702                 if (dirname != NULL) {
703                         struct smb_filename *smb_fname_dir =
704                                 synthetic_smb_fname(talloc_tos(),
705                                                 dirname,
706                                                 NULL,
707                                                 NULL);
708                         if (smb_fname_dir == NULL) {
709                                 TALLOC_FREE(smb_fname_base);
710                                 TALLOC_FREE(dirname);
711                                 errno = ENOMEM;
712                                 return -1;
713                         }
714                         SMB_VFS_NEXT_RMDIR(handle, smb_fname_dir);
715                         TALLOC_FREE(smb_fname_dir);
716                 }
717                 TALLOC_FREE(dirname);
718         }
719
720         TALLOC_FREE(smb_fname_base);
721         return ret;
722 }
723
724 static int streams_depot_rmdir(vfs_handle_struct *handle,
725                                 const struct smb_filename *smb_fname)
726 {
727         struct smb_filename *smb_fname_base = NULL;
728         int ret = -1;
729
730         DEBUG(10, ("streams_depot_rmdir called for %s\n",
731                 smb_fname->base_name));
732
733         /*
734          * We potentially need to delete the per-inode streams directory
735          */
736
737         smb_fname_base = synthetic_smb_fname(talloc_tos(),
738                                 smb_fname->base_name,
739                                 NULL,
740                                 NULL);
741         if (smb_fname_base == NULL) {
742                 errno = ENOMEM;
743                 return -1;
744         }
745
746         if (lp_posix_pathnames()) {
747                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
748         } else {
749                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
750         }
751
752         if (ret == -1) {
753                 TALLOC_FREE(smb_fname_base);
754                 return -1;
755         }
756
757         ret = SMB_VFS_NEXT_RMDIR(handle, smb_fname_base);
758         if (ret == 0) {
759                 char *dirname = stream_dir(handle, smb_fname_base,
760                                            &smb_fname_base->st, false);
761
762                 if (dirname != NULL) {
763                         struct smb_filename *smb_fname_dir =
764                                 synthetic_smb_fname(talloc_tos(),
765                                                 dirname,
766                                                 NULL,
767                                                 NULL);
768                         if (smb_fname_dir == NULL) {
769                                 TALLOC_FREE(smb_fname_base);
770                                 TALLOC_FREE(dirname);
771                                 errno = ENOMEM;
772                                 return -1;
773                         }
774                         SMB_VFS_NEXT_RMDIR(handle, smb_fname_dir);
775                         TALLOC_FREE(smb_fname_dir);
776                 }
777                 TALLOC_FREE(dirname);
778         }
779
780         TALLOC_FREE(smb_fname_base);
781         return ret;
782 }
783
784 static int streams_depot_rename(vfs_handle_struct *handle,
785                                 const struct smb_filename *smb_fname_src,
786                                 const struct smb_filename *smb_fname_dst)
787 {
788         struct smb_filename *smb_fname_src_stream = NULL;
789         struct smb_filename *smb_fname_dst_stream = NULL;
790         bool src_is_stream, dst_is_stream;
791         NTSTATUS status;
792         int ret = -1;
793
794         DEBUG(10, ("streams_depot_rename called for %s => %s\n",
795                    smb_fname_str_dbg(smb_fname_src),
796                    smb_fname_str_dbg(smb_fname_dst)));
797
798         src_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
799         dst_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
800
801         if (!src_is_stream && !dst_is_stream) {
802                 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
803                                            smb_fname_dst);
804         }
805
806         /* for now don't allow renames from or to the default stream */
807         if (is_ntfs_default_stream_smb_fname(smb_fname_src) ||
808             is_ntfs_default_stream_smb_fname(smb_fname_dst)) {
809                 errno = ENOSYS;
810                 goto done;
811         }
812
813         status = stream_smb_fname(handle, smb_fname_src, &smb_fname_src_stream,
814                                   false);
815         if (!NT_STATUS_IS_OK(status)) {
816                 errno = map_errno_from_nt_status(status);
817                 goto done;
818         }
819
820         status = stream_smb_fname(handle, smb_fname_dst,
821                                   &smb_fname_dst_stream, false);
822         if (!NT_STATUS_IS_OK(status)) {
823                 errno = map_errno_from_nt_status(status);
824                 goto done;
825         }
826
827         ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src_stream,
828                                   smb_fname_dst_stream);
829
830 done:
831         TALLOC_FREE(smb_fname_src_stream);
832         TALLOC_FREE(smb_fname_dst_stream);
833         return ret;
834 }
835
836 static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
837                            struct stream_struct **streams,
838                            const char *name, off_t size,
839                            off_t alloc_size)
840 {
841         struct stream_struct *tmp;
842
843         tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
844                                    (*num_streams)+1);
845         if (tmp == NULL) {
846                 return false;
847         }
848
849         tmp[*num_streams].name = talloc_strdup(tmp, name);
850         if (tmp[*num_streams].name == NULL) {
851                 return false;
852         }
853
854         tmp[*num_streams].size = size;
855         tmp[*num_streams].alloc_size = alloc_size;
856
857         *streams = tmp;
858         *num_streams += 1;
859         return true;
860 }
861
862 struct streaminfo_state {
863         TALLOC_CTX *mem_ctx;
864         vfs_handle_struct *handle;
865         unsigned int num_streams;
866         struct stream_struct *streams;
867         NTSTATUS status;
868 };
869
870 static bool collect_one_stream(const char *dirname,
871                                const char *dirent,
872                                void *private_data)
873 {
874         struct streaminfo_state *state =
875                 (struct streaminfo_state *)private_data;
876         struct smb_filename *smb_fname = NULL;
877         char *sname = NULL;
878         bool ret;
879
880         sname = talloc_asprintf(talloc_tos(), "%s/%s", dirname, dirent);
881         if (sname == NULL) {
882                 state->status = NT_STATUS_NO_MEMORY;
883                 ret = false;
884                 goto out;
885         }
886
887         smb_fname = synthetic_smb_fname(talloc_tos(), sname, NULL, NULL);
888         if (smb_fname == NULL) {
889                 state->status = NT_STATUS_NO_MEMORY;
890                 ret = false;
891                 goto out;
892         }
893
894         if (SMB_VFS_NEXT_STAT(state->handle, smb_fname) == -1) {
895                 DEBUG(10, ("Could not stat %s: %s\n", sname,
896                            strerror(errno)));
897                 ret = true;
898                 goto out;
899         }
900
901         if (!add_one_stream(state->mem_ctx,
902                             &state->num_streams, &state->streams,
903                             dirent, smb_fname->st.st_ex_size,
904                             SMB_VFS_GET_ALLOC_SIZE(state->handle->conn, NULL,
905                                                    &smb_fname->st))) {
906                 state->status = NT_STATUS_NO_MEMORY;
907                 ret = false;
908                 goto out;
909         }
910
911         ret = true;
912  out:
913         TALLOC_FREE(sname);
914         TALLOC_FREE(smb_fname);
915         return ret;
916 }
917
918 static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
919                                          struct files_struct *fsp,
920                                          const struct smb_filename *smb_fname,
921                                          TALLOC_CTX *mem_ctx,
922                                          unsigned int *pnum_streams,
923                                          struct stream_struct **pstreams)
924 {
925         struct smb_filename *smb_fname_base = NULL;
926         int ret;
927         NTSTATUS status;
928         struct streaminfo_state state;
929
930         smb_fname_base = synthetic_smb_fname(talloc_tos(),
931                                         smb_fname->base_name,
932                                         NULL,
933                                         NULL);
934         if (smb_fname_base == NULL) {
935                 return NT_STATUS_NO_MEMORY;
936         }
937
938         if ((fsp != NULL) && (fsp->fh->fd != -1)) {
939                 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &smb_fname_base->st);
940         }
941         else {
942                 if (lp_posix_pathnames()) {
943                         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
944                 } else {
945                         ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
946                 }
947         }
948
949         if (ret == -1) {
950                 status = map_nt_error_from_unix(errno);
951                 goto out;
952         }
953
954         state.streams = *pstreams;
955         state.num_streams = *pnum_streams;
956         state.mem_ctx = mem_ctx;
957         state.handle = handle;
958         state.status = NT_STATUS_OK;
959
960         if (S_ISLNK(smb_fname_base->st.st_ex_mode)) {
961                 /*
962                  * Currently we do't have SMB_VFS_LLISTXATTR
963                  * inside the VFS which means there's no way
964                  * to cope with a symlink when lp_posix_pathnames().
965                  * returns true. For now ignore links.
966                  * FIXME - by adding SMB_VFS_LLISTXATTR. JRA.
967                  */
968                 status = NT_STATUS_OK;
969         } else {
970                 status = walk_streams(handle, smb_fname_base, NULL, collect_one_stream,
971                               &state);
972         }
973
974         if (!NT_STATUS_IS_OK(status)) {
975                 TALLOC_FREE(state.streams);
976                 goto out;
977         }
978
979         if (!NT_STATUS_IS_OK(state.status)) {
980                 TALLOC_FREE(state.streams);
981                 status = state.status;
982                 goto out;
983         }
984
985         *pnum_streams = state.num_streams;
986         *pstreams = state.streams;
987         status = SMB_VFS_NEXT_STREAMINFO(handle,
988                                 fsp,
989                                 smb_fname_base,
990                                 mem_ctx,
991                                 pnum_streams,
992                                 pstreams);
993
994  out:
995         TALLOC_FREE(smb_fname_base);
996         return status;
997 }
998
999 static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle,
1000                         enum timestamp_set_resolution *p_ts_res)
1001 {
1002         return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS;
1003 }
1004
1005 static struct vfs_fn_pointers vfs_streams_depot_fns = {
1006         .fs_capabilities_fn = streams_depot_fs_capabilities,
1007         .open_fn = streams_depot_open,
1008         .stat_fn = streams_depot_stat,
1009         .lstat_fn = streams_depot_lstat,
1010         .unlink_fn = streams_depot_unlink,
1011         .rmdir_fn = streams_depot_rmdir,
1012         .rename_fn = streams_depot_rename,
1013         .streaminfo_fn = streams_depot_streaminfo,
1014 };
1015
1016 NTSTATUS vfs_streams_depot_init(void);
1017 NTSTATUS vfs_streams_depot_init(void)
1018 {
1019         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
1020                                 &vfs_streams_depot_fns);
1021 }