s3: VFS: Change SMB_VFS_GETXATTR to use const struct smb_filename * instead of const...
[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,
71                         const struct smb_filename *smb_fname)
72 {
73         char buf;
74
75         DEBUG(10, ("file_is_valid (%s) called\n", smb_fname->base_name));
76
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;
81         }
82
83         if (buf != '1') {
84                 DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
85                 return false;
86         }
87
88         return true;
89 }
90
91 static bool mark_file_valid(vfs_handle_struct *handle,
92                                 const struct smb_filename *smb_fname)
93 {
94         char buf = '1';
95         int ret;
96
97         DEBUG(10, ("marking file %s as valid\n", smb_fname->base_name));
98
99         ret = SMB_VFS_SETXATTR(handle->conn, smb_fname, SAMBA_XATTR_MARKER,
100                                     &buf, sizeof(buf), 0);
101
102         if (ret == -1) {
103                 DEBUG(10, ("SETXATTR failed: %s\n", strerror(errno)));
104                 return false;
105         }
106
107         return true;
108 }
109
110 /**
111  * Given an smb_filename, determine the stream directory using the file's
112  * base_name.
113  */
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)
117 {
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;
131
132         check_valid = lp_parm_bool(SNUM(handle->conn),
133                       "streams_depot", "check_valid", true);
134
135         tmp = talloc_asprintf(talloc_tos(), "%s/.streams",
136                 handle->conn->connectpath);
137
138         if (tmp == NULL) {
139                 errno = ENOMEM;
140                 goto fail;
141         }
142
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;
149         }
150
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;
159         }
160
161         /* Stat the base file if it hasn't already been done. */
162         if (base_sbuf == NULL) {
163                 struct smb_filename *smb_fname_base;
164
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;
174                 }
175                 if (SMB_VFS_NEXT_STAT(handle, smb_fname_base) == -1) {
176                         TALLOC_FREE(smb_fname_base);
177                         goto fail;
178                 }
179                 base_sbuf_tmp = smb_fname_base->st;
180                 TALLOC_FREE(smb_fname_base);
181         } else {
182                 base_sbuf_tmp = *base_sbuf;
183         }
184
185         id = SMB_VFS_FILE_ID_CREATE(handle->conn, &base_sbuf_tmp);
186
187         push_file_id_16((char *)id_buf, &id);
188
189         hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf)));
190
191         first = hash & 0xff;
192         second = (hash >> 8) & 0xff;
193
194         id_hex = hex_encode_talloc(talloc_tos(), id_buf, sizeof(id_buf));
195
196         if (id_hex == NULL) {
197                 errno = ENOMEM;
198                 goto fail;
199         }
200
201         result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir,
202                                  first, second, id_hex);
203
204         TALLOC_FREE(id_hex);
205
206         if (result == NULL) {
207                 errno = ENOMEM;
208                 return NULL;
209         }
210
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;
219         }
220
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;
225
226                 if (!S_ISDIR(smb_fname_hash->st.st_ex_mode)) {
227                         errno = EINVAL;
228                         goto fail;
229                 }
230
231                 if (!check_valid ||
232                     file_is_valid(handle, smb_fname)) {
233                         return result;
234                 }
235
236                 /*
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.
240                  */
241
242         again:
243                 delete_lost = lp_parm_bool(SNUM(handle->conn), "streams_depot",
244                                            "delete_lost", false);
245
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;
263                         }
264
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;
275                         }
276
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;
282                                 }
283                                 goto fail;
284                         }
285
286                         TALLOC_FREE(smb_fname_new);
287                 }
288         }
289
290         if (!create_it) {
291                 errno = ENOENT;
292                 goto fail;
293         }
294
295         if ((SMB_VFS_NEXT_MKDIR(handle, rootdir_fname, 0755) != 0)
296             && (errno != EEXIST)) {
297                 goto fail;
298         }
299
300         tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
301         if (tmp == NULL) {
302                 errno = ENOMEM;
303                 goto fail;
304         }
305
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;
314         }
315
316         if ((SMB_VFS_NEXT_MKDIR(handle, tmp_fname, 0755) != 0)
317             && (errno != EEXIST)) {
318                 goto fail;
319         }
320
321         TALLOC_FREE(tmp);
322         TALLOC_FREE(tmp_fname);
323
324         tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
325                               second);
326         if (tmp == NULL) {
327                 errno = ENOMEM;
328                 goto fail;
329         }
330
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;
339         }
340
341         if ((SMB_VFS_NEXT_MKDIR(handle, tmp_fname, 0755) != 0)
342             && (errno != EEXIST)) {
343                 goto fail;
344         }
345
346         TALLOC_FREE(tmp);
347         TALLOC_FREE(tmp_fname);
348
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;
353         }
354
355         if (check_valid && !mark_file_valid(handle, smb_fname)) {
356                 goto fail;
357         }
358
359         TALLOC_FREE(rootdir_fname);
360         TALLOC_FREE(rootdir);
361         TALLOC_FREE(tmp_fname);
362         TALLOC_FREE(smb_fname_hash);
363         return result;
364
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;
372 }
373 /**
374  * Given a stream name, populate smb_fname_out with the actual location of the
375  * stream.
376  */
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)
381 {
382         char *dirname, *stream_fname;
383         const char *stype;
384         NTSTATUS status;
385
386         *smb_fname_out = NULL;
387
388         stype = strchr_m(smb_fname->stream_name + 1, ':');
389
390         if (stype) {
391                 if (strcasecmp_m(stype, ":$DATA") != 0) {
392                         return NT_STATUS_INVALID_PARAMETER;
393                 }
394         }
395
396         dirname = stream_dir(handle, smb_fname, NULL, create_dir);
397
398         if (dirname == NULL) {
399                 status = map_nt_error_from_unix(errno);
400                 goto fail;
401         }
402
403         stream_fname = talloc_asprintf(talloc_tos(), "%s/%s", dirname,
404                                        smb_fname->stream_name);
405
406         if (stream_fname == NULL) {
407                 status = NT_STATUS_NO_MEMORY;
408                 goto fail;
409         }
410
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;
418                 }
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;
424                 }
425         }
426
427         DEBUG(10, ("stream filename = %s\n", stream_fname));
428
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;
437         }
438
439         return NT_STATUS_OK;
440
441  fail:
442         DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
443         TALLOC_FREE(*smb_fname_out);
444         return status;
445 }
446
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)
454 {
455         char *dirname;
456         struct smb_filename *dir_smb_fname = NULL;
457         DIR *dirhandle = NULL;
458         const char *dirent = NULL;
459         char *talloced = NULL;
460
461         dirname = stream_dir(handle, smb_fname_base, &smb_fname_base->st,
462                              false);
463
464         if (dirname == NULL) {
465                 if (errno == ENOENT) {
466                         /*
467                          * no stream around
468                          */
469                         return NT_STATUS_OK;
470                 }
471                 return map_nt_error_from_unix(errno);
472         }
473
474         DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
475
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;
484         }
485
486         dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dir_smb_fname, NULL, 0);
487
488         TALLOC_FREE(dir_smb_fname);
489
490         if (dirhandle == NULL) {
491                 TALLOC_FREE(dirname);
492                 return map_nt_error_from_unix(errno);
493         }
494
495         while ((dirent = vfs_readdirname(handle->conn, dirhandle, NULL,
496                                          &talloced)) != NULL) {
497
498                 if (ISDOT(dirent) || ISDOTDOT(dirent)) {
499                         TALLOC_FREE(talloced);
500                         continue;
501                 }
502
503                 DEBUG(10, ("walk_streams: dirent=%s\n", dirent));
504
505                 if (!fn(dirname, dirent, private_data)) {
506                         TALLOC_FREE(talloced);
507                         break;
508                 }
509                 TALLOC_FREE(talloced);
510         }
511
512         SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle);
513
514         if (pdirname != NULL) {
515                 *pdirname = dirname;
516         }
517         else {
518                 TALLOC_FREE(dirname);
519         }
520
521         return NT_STATUS_OK;
522 }
523
524 /**
525  * Helper to stat/lstat the base file of an smb_fname. This will actually
526  * fills in the stat struct in smb_filename.
527  */
528 static int streams_depot_stat_base(vfs_handle_struct *handle,
529                                    struct smb_filename *smb_fname,
530                                    bool follow_links)
531 {
532         char *tmp_stream_name;
533         int result;
534
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);
541         }
542         smb_fname->stream_name = tmp_stream_name;
543         return result;
544 }
545
546 static int streams_depot_stat(vfs_handle_struct *handle,
547                               struct smb_filename *smb_fname)
548 {
549         struct smb_filename *smb_fname_stream = NULL;
550         NTSTATUS status;
551         int ret = -1;
552
553         DEBUG(10, ("streams_depot_stat called for [%s]\n",
554                    smb_fname_str_dbg(smb_fname)));
555
556         if (!is_ntfs_stream_smb_fname(smb_fname)) {
557                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
558         }
559
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);
563         }
564
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;
572         }
573
574         ret = SMB_VFS_NEXT_STAT(handle, smb_fname_stream);
575
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;
581 }
582
583
584
585 static int streams_depot_lstat(vfs_handle_struct *handle,
586                                struct smb_filename *smb_fname)
587 {
588         struct smb_filename *smb_fname_stream = NULL;
589         NTSTATUS status;
590         int ret = -1;
591
592         DEBUG(10, ("streams_depot_lstat called for [%s]\n",
593                    smb_fname_str_dbg(smb_fname)));
594
595         if (!is_ntfs_stream_smb_fname(smb_fname)) {
596                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
597         }
598
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);
602         }
603
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;
611         }
612
613         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_stream);
614
615  done:
616         TALLOC_FREE(smb_fname_stream);
617         return ret;
618 }
619
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)
623 {
624         struct smb_filename *smb_fname_stream = NULL;
625         struct smb_filename *smb_fname_base = NULL;
626         NTSTATUS status;
627         int ret = -1;
628
629         if (!is_ntfs_stream_smb_fname(smb_fname)) {
630                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
631         }
632
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;
636
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;
641
642                 return ret;
643         }
644
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;
655         }
656
657         ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
658         if (ret == -1) {
659                 goto done;
660         }
661
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;
668         }
669
670         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname_stream, fsp, flags, mode);
671
672  done:
673         TALLOC_FREE(smb_fname_stream);
674         TALLOC_FREE(smb_fname_base);
675         return ret;
676 }
677
678 static int streams_depot_unlink(vfs_handle_struct *handle,
679                                 const struct smb_filename *smb_fname)
680 {
681         struct smb_filename *smb_fname_base = NULL;
682         int ret = -1;
683
684         DEBUG(10, ("streams_depot_unlink called for %s\n",
685                    smb_fname_str_dbg(smb_fname)));
686
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;
692
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;
698                 }
699
700                 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_stream);
701
702                 TALLOC_FREE(smb_fname_stream);
703                 return ret;
704         }
705
706         /*
707          * We potentially need to delete the per-inode streams directory
708          */
709
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;
718         }
719
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);
724         }
725
726         if (ret == -1) {
727                 TALLOC_FREE(smb_fname_base);
728                 return -1;
729         }
730
731         /*
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.
735          */
736         {
737                 char *dirname = stream_dir(handle, smb_fname_base,
738                                            &smb_fname_base->st, false);
739
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;
752                         }
753                         SMB_VFS_NEXT_RMDIR(handle, smb_fname_dir);
754                         TALLOC_FREE(smb_fname_dir);
755                 }
756                 TALLOC_FREE(dirname);
757         }
758
759         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
760         TALLOC_FREE(smb_fname_base);
761         return ret;
762 }
763
764 static int streams_depot_rmdir(vfs_handle_struct *handle,
765                                 const struct smb_filename *smb_fname)
766 {
767         struct smb_filename *smb_fname_base = NULL;
768         int ret = -1;
769
770         DEBUG(10, ("streams_depot_rmdir called for %s\n",
771                 smb_fname->base_name));
772
773         /*
774          * We potentially need to delete the per-inode streams directory
775          */
776
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;
785         }
786
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);
791         }
792
793         if (ret == -1) {
794                 TALLOC_FREE(smb_fname_base);
795                 return -1;
796         }
797
798         /*
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.
802          */
803         {
804                 char *dirname = stream_dir(handle, smb_fname_base,
805                                            &smb_fname_base->st, false);
806
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;
819                         }
820                         SMB_VFS_NEXT_RMDIR(handle, smb_fname_dir);
821                         TALLOC_FREE(smb_fname_dir);
822                 }
823                 TALLOC_FREE(dirname);
824         }
825
826         ret = SMB_VFS_NEXT_RMDIR(handle, smb_fname_base);
827         TALLOC_FREE(smb_fname_base);
828         return ret;
829 }
830
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)
834 {
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;
840
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)));
844
845         src_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
846         dst_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
847
848         if (!src_is_stream && !dst_is_stream) {
849                 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
850                                            smb_fname_dst);
851         }
852
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;
858         }
859
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;
865         }
866
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;
872         }
873
874         ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src_stream,
875                                   smb_fname_dst_stream);
876
877 done:
878         TALLOC_FREE(smb_fname_src_stream);
879         TALLOC_FREE(smb_fname_dst_stream);
880         return ret;
881 }
882
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)
887 {
888         struct stream_struct *tmp;
889
890         tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
891                                    (*num_streams)+1);
892         if (tmp == NULL) {
893                 return false;
894         }
895
896         tmp[*num_streams].name = talloc_strdup(tmp, name);
897         if (tmp[*num_streams].name == NULL) {
898                 return false;
899         }
900
901         tmp[*num_streams].size = size;
902         tmp[*num_streams].alloc_size = alloc_size;
903
904         *streams = tmp;
905         *num_streams += 1;
906         return true;
907 }
908
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;
915 };
916
917 static bool collect_one_stream(const char *dirname,
918                                const char *dirent,
919                                void *private_data)
920 {
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;
926
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;
932         }
933
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;
939         }
940
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;
946         }
947
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;
956         }
957
958         ret = true;
959  out:
960         TALLOC_FREE(sname);
961         TALLOC_FREE(smb_fname);
962         return ret;
963 }
964
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)
971 {
972         struct smb_filename *smb_fname_base = NULL;
973         int ret;
974         NTSTATUS status;
975         struct streaminfo_state state;
976
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;
984         }
985
986         if ((fsp != NULL) && (fsp->fh->fd != -1)) {
987                 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &smb_fname_base->st);
988         }
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);
994                 }
995         }
996
997         if (ret == -1) {
998                 status = map_nt_error_from_unix(errno);
999                 goto out;
1000         }
1001
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;
1007
1008         if (S_ISLNK(smb_fname_base->st.st_ex_mode)) {
1009                 /*
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.
1015                  */
1016                 status = NT_STATUS_OK;
1017         } else {
1018                 status = walk_streams(handle, smb_fname_base, NULL, collect_one_stream,
1019                               &state);
1020         }
1021
1022         if (!NT_STATUS_IS_OK(status)) {
1023                 TALLOC_FREE(state.streams);
1024                 goto out;
1025         }
1026
1027         if (!NT_STATUS_IS_OK(state.status)) {
1028                 TALLOC_FREE(state.streams);
1029                 status = state.status;
1030                 goto out;
1031         }
1032
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);
1041
1042  out:
1043         TALLOC_FREE(smb_fname_base);
1044         return status;
1045 }
1046
1047 static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle,
1048                         enum timestamp_set_resolution *p_ts_res)
1049 {
1050         return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS;
1051 }
1052
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,
1062 };
1063
1064 NTSTATUS vfs_streams_depot_init(TALLOC_CTX *);
1065 NTSTATUS vfs_streams_depot_init(TALLOC_CTX *ctx)
1066 {
1067         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
1068                                 &vfs_streams_depot_fns);
1069 }