s3: VFS: vfs_streams_depot: Change to using SMB_VFS_RENAMEAT() instead of SMB_VFS_REN...
[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_RENAMEAT(handle,
278                                         handle->conn->cwd_fsp,
279                                         smb_fname_hash,
280                                         handle->conn->cwd_fsp,
281                                         smb_fname_new) == -1) {
282                                 TALLOC_FREE(smb_fname_new);
283                                 if ((errno == EEXIST) || (errno == ENOTEMPTY)) {
284                                         goto again;
285                                 }
286                                 goto fail;
287                         }
288
289                         TALLOC_FREE(smb_fname_new);
290                 }
291         }
292
293         if (!create_it) {
294                 errno = ENOENT;
295                 goto fail;
296         }
297
298         if ((SMB_VFS_NEXT_MKDIR(handle, rootdir_fname, 0755) != 0)
299             && (errno != EEXIST)) {
300                 goto fail;
301         }
302
303         tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
304         if (tmp == NULL) {
305                 errno = ENOMEM;
306                 goto fail;
307         }
308
309         tmp_fname = synthetic_smb_fname(talloc_tos(),
310                                         tmp,
311                                         NULL,
312                                         NULL,
313                                         smb_fname->flags);
314         if (tmp_fname == NULL) {
315                 errno = ENOMEM;
316                 goto fail;
317         }
318
319         if ((SMB_VFS_NEXT_MKDIR(handle, tmp_fname, 0755) != 0)
320             && (errno != EEXIST)) {
321                 goto fail;
322         }
323
324         TALLOC_FREE(tmp);
325         TALLOC_FREE(tmp_fname);
326
327         tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
328                               second);
329         if (tmp == NULL) {
330                 errno = ENOMEM;
331                 goto fail;
332         }
333
334         tmp_fname = synthetic_smb_fname(talloc_tos(),
335                                         tmp,
336                                         NULL,
337                                         NULL,
338                                         smb_fname->flags);
339         if (tmp_fname == NULL) {
340                 errno = ENOMEM;
341                 goto fail;
342         }
343
344         if ((SMB_VFS_NEXT_MKDIR(handle, tmp_fname, 0755) != 0)
345             && (errno != EEXIST)) {
346                 goto fail;
347         }
348
349         TALLOC_FREE(tmp);
350         TALLOC_FREE(tmp_fname);
351
352         /* smb_fname_hash is the struct smb_filename version of 'result' */
353         if ((SMB_VFS_NEXT_MKDIR(handle, smb_fname_hash, 0755) != 0)
354             && (errno != EEXIST)) {
355                 goto fail;
356         }
357
358         if (check_valid && !mark_file_valid(handle, smb_fname)) {
359                 goto fail;
360         }
361
362         TALLOC_FREE(rootdir_fname);
363         TALLOC_FREE(rootdir);
364         TALLOC_FREE(tmp_fname);
365         TALLOC_FREE(smb_fname_hash);
366         return result;
367
368  fail:
369         TALLOC_FREE(rootdir_fname);
370         TALLOC_FREE(rootdir);
371         TALLOC_FREE(tmp_fname);
372         TALLOC_FREE(smb_fname_hash);
373         TALLOC_FREE(result);
374         return NULL;
375 }
376 /**
377  * Given a stream name, populate smb_fname_out with the actual location of the
378  * stream.
379  */
380 static NTSTATUS stream_smb_fname(vfs_handle_struct *handle,
381                                  const struct smb_filename *smb_fname,
382                                  struct smb_filename **smb_fname_out,
383                                  bool create_dir)
384 {
385         char *dirname, *stream_fname;
386         const char *stype;
387         NTSTATUS status;
388
389         *smb_fname_out = NULL;
390
391         stype = strchr_m(smb_fname->stream_name + 1, ':');
392
393         if (stype) {
394                 if (strcasecmp_m(stype, ":$DATA") != 0) {
395                         return NT_STATUS_INVALID_PARAMETER;
396                 }
397         }
398
399         dirname = stream_dir(handle, smb_fname, NULL, create_dir);
400
401         if (dirname == NULL) {
402                 status = map_nt_error_from_unix(errno);
403                 goto fail;
404         }
405
406         stream_fname = talloc_asprintf(talloc_tos(), "%s/%s", dirname,
407                                        smb_fname->stream_name);
408
409         if (stream_fname == NULL) {
410                 status = NT_STATUS_NO_MEMORY;
411                 goto fail;
412         }
413
414         if (stype == NULL) {
415                 /* Append an explicit stream type if one wasn't specified. */
416                 stream_fname = talloc_asprintf(talloc_tos(), "%s:$DATA",
417                                                stream_fname);
418                 if (stream_fname == NULL) {
419                         status = NT_STATUS_NO_MEMORY;
420                         goto fail;
421                 }
422         } else {
423                 /* Normalize the stream type to upercase. */
424                 if (!strupper_m(strrchr_m(stream_fname, ':') + 1)) {
425                         status = NT_STATUS_INVALID_PARAMETER;
426                         goto fail;
427                 }
428         }
429
430         DEBUG(10, ("stream filename = %s\n", stream_fname));
431
432         /* Create an smb_filename with stream_name == NULL. */
433         *smb_fname_out = synthetic_smb_fname(talloc_tos(),
434                                         stream_fname,
435                                         NULL,
436                                         NULL,
437                                         smb_fname->flags);
438         if (*smb_fname_out == NULL) {
439                 return NT_STATUS_NO_MEMORY;
440         }
441
442         return NT_STATUS_OK;
443
444  fail:
445         DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
446         TALLOC_FREE(*smb_fname_out);
447         return status;
448 }
449
450 static NTSTATUS walk_streams(vfs_handle_struct *handle,
451                              struct smb_filename *smb_fname_base,
452                              char **pdirname,
453                              bool (*fn)(const char *dirname,
454                                         const char *dirent,
455                                         void *private_data),
456                              void *private_data)
457 {
458         char *dirname;
459         struct smb_filename *dir_smb_fname = NULL;
460         DIR *dirhandle = NULL;
461         const char *dirent = NULL;
462         char *talloced = NULL;
463
464         dirname = stream_dir(handle, smb_fname_base, &smb_fname_base->st,
465                              false);
466
467         if (dirname == NULL) {
468                 if (errno == ENOENT) {
469                         /*
470                          * no stream around
471                          */
472                         return NT_STATUS_OK;
473                 }
474                 return map_nt_error_from_unix(errno);
475         }
476
477         DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
478
479         dir_smb_fname = synthetic_smb_fname(talloc_tos(),
480                                         dirname,
481                                         NULL,
482                                         NULL,
483                                         smb_fname_base->flags);
484         if (dir_smb_fname == NULL) {
485                 TALLOC_FREE(dirname);
486                 return NT_STATUS_NO_MEMORY;
487         }
488
489         dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dir_smb_fname, NULL, 0);
490
491         TALLOC_FREE(dir_smb_fname);
492
493         if (dirhandle == NULL) {
494                 TALLOC_FREE(dirname);
495                 return map_nt_error_from_unix(errno);
496         }
497
498         while ((dirent = vfs_readdirname(handle->conn, dirhandle, NULL,
499                                          &talloced)) != NULL) {
500
501                 if (ISDOT(dirent) || ISDOTDOT(dirent)) {
502                         TALLOC_FREE(talloced);
503                         continue;
504                 }
505
506                 DEBUG(10, ("walk_streams: dirent=%s\n", dirent));
507
508                 if (!fn(dirname, dirent, private_data)) {
509                         TALLOC_FREE(talloced);
510                         break;
511                 }
512                 TALLOC_FREE(talloced);
513         }
514
515         SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle);
516
517         if (pdirname != NULL) {
518                 *pdirname = dirname;
519         }
520         else {
521                 TALLOC_FREE(dirname);
522         }
523
524         return NT_STATUS_OK;
525 }
526
527 /**
528  * Helper to stat/lstat the base file of an smb_fname. This will actually
529  * fills in the stat struct in smb_filename.
530  */
531 static int streams_depot_stat_base(vfs_handle_struct *handle,
532                                    struct smb_filename *smb_fname,
533                                    bool follow_links)
534 {
535         char *tmp_stream_name;
536         int result;
537
538         tmp_stream_name = smb_fname->stream_name;
539         smb_fname->stream_name = NULL;
540         if (follow_links) {
541                 result = SMB_VFS_NEXT_STAT(handle, smb_fname);
542         } else {
543                 result = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
544         }
545         smb_fname->stream_name = tmp_stream_name;
546         return result;
547 }
548
549 static int streams_depot_stat(vfs_handle_struct *handle,
550                               struct smb_filename *smb_fname)
551 {
552         struct smb_filename *smb_fname_stream = NULL;
553         NTSTATUS status;
554         int ret = -1;
555
556         DEBUG(10, ("streams_depot_stat called for [%s]\n",
557                    smb_fname_str_dbg(smb_fname)));
558
559         if (!is_ntfs_stream_smb_fname(smb_fname)) {
560                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
561         }
562
563         /* If the default stream is requested, just stat the base file. */
564         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
565                 return streams_depot_stat_base(handle, smb_fname, true);
566         }
567
568         /* Stat the actual stream now. */
569         status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
570                                   false);
571         if (!NT_STATUS_IS_OK(status)) {
572                 ret = -1;
573                 errno = map_errno_from_nt_status(status);
574                 goto done;
575         }
576
577         ret = SMB_VFS_NEXT_STAT(handle, smb_fname_stream);
578
579         /* Update the original smb_fname with the stat info. */
580         smb_fname->st = smb_fname_stream->st;
581  done:
582         TALLOC_FREE(smb_fname_stream);
583         return ret;
584 }
585
586
587
588 static int streams_depot_lstat(vfs_handle_struct *handle,
589                                struct smb_filename *smb_fname)
590 {
591         struct smb_filename *smb_fname_stream = NULL;
592         NTSTATUS status;
593         int ret = -1;
594
595         DEBUG(10, ("streams_depot_lstat called for [%s]\n",
596                    smb_fname_str_dbg(smb_fname)));
597
598         if (!is_ntfs_stream_smb_fname(smb_fname)) {
599                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
600         }
601
602         /* If the default stream is requested, just stat the base file. */
603         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
604                 return streams_depot_stat_base(handle, smb_fname, false);
605         }
606
607         /* Stat the actual stream now. */
608         status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
609                                   false);
610         if (!NT_STATUS_IS_OK(status)) {
611                 ret = -1;
612                 errno = map_errno_from_nt_status(status);
613                 goto done;
614         }
615
616         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_stream);
617
618  done:
619         TALLOC_FREE(smb_fname_stream);
620         return ret;
621 }
622
623 static int streams_depot_open(vfs_handle_struct *handle,
624                               struct smb_filename *smb_fname,
625                               files_struct *fsp, int flags, mode_t mode)
626 {
627         struct smb_filename *smb_fname_stream = NULL;
628         struct smb_filename *smb_fname_base = NULL;
629         NTSTATUS status;
630         int ret = -1;
631
632         if (!is_ntfs_stream_smb_fname(smb_fname)) {
633                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
634         }
635
636         /* If the default stream is requested, just open the base file. */
637         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
638                 char *tmp_stream_name;
639
640                 tmp_stream_name = smb_fname->stream_name;
641                 smb_fname->stream_name = NULL;
642                 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
643                 smb_fname->stream_name = tmp_stream_name;
644
645                 return ret;
646         }
647
648         /* Ensure the base file still exists. */
649         smb_fname_base = synthetic_smb_fname(talloc_tos(),
650                                         smb_fname->base_name,
651                                         NULL,
652                                         NULL,
653                                         smb_fname->flags);
654         if (smb_fname_base == NULL) {
655                 ret = -1;
656                 errno = ENOMEM;
657                 goto done;
658         }
659
660         ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
661         if (ret == -1) {
662                 goto done;
663         }
664
665         /* Determine the stream name, and then open it. */
666         status = stream_smb_fname(handle, smb_fname, &smb_fname_stream, true);
667         if (!NT_STATUS_IS_OK(status)) {
668                 ret = -1;
669                 errno = map_errno_from_nt_status(status);
670                 goto done;
671         }
672
673         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname_stream, fsp, flags, mode);
674
675  done:
676         TALLOC_FREE(smb_fname_stream);
677         TALLOC_FREE(smb_fname_base);
678         return ret;
679 }
680
681 static int streams_depot_unlink(vfs_handle_struct *handle,
682                                 const struct smb_filename *smb_fname)
683 {
684         struct smb_filename *smb_fname_base = NULL;
685         int ret = -1;
686
687         DEBUG(10, ("streams_depot_unlink called for %s\n",
688                    smb_fname_str_dbg(smb_fname)));
689
690         /* If there is a valid stream, just unlink the stream and return. */
691         if (is_ntfs_stream_smb_fname(smb_fname) &&
692             !is_ntfs_default_stream_smb_fname(smb_fname)) {
693                 struct smb_filename *smb_fname_stream = NULL;
694                 NTSTATUS status;
695
696                 status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
697                                           false);
698                 if (!NT_STATUS_IS_OK(status)) {
699                         errno = map_errno_from_nt_status(status);
700                         return -1;
701                 }
702
703                 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_stream);
704
705                 TALLOC_FREE(smb_fname_stream);
706                 return ret;
707         }
708
709         /*
710          * We potentially need to delete the per-inode streams directory
711          */
712
713         smb_fname_base = synthetic_smb_fname(talloc_tos(),
714                                         smb_fname->base_name,
715                                         NULL,
716                                         NULL,
717                                         smb_fname->flags);
718         if (smb_fname_base == NULL) {
719                 errno = ENOMEM;
720                 return -1;
721         }
722
723         if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
724                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
725         } else {
726                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
727         }
728
729         if (ret == -1) {
730                 TALLOC_FREE(smb_fname_base);
731                 return -1;
732         }
733
734         /*
735          * We know the unlink should succeed as the ACL
736          * check is already done in the caller. Remove the
737          * file *after* the streams.
738          */
739         {
740                 char *dirname = stream_dir(handle, smb_fname_base,
741                                            &smb_fname_base->st, false);
742
743                 if (dirname != NULL) {
744                         struct smb_filename *smb_fname_dir =
745                                 synthetic_smb_fname(talloc_tos(),
746                                                 dirname,
747                                                 NULL,
748                                                 NULL,
749                                                 smb_fname->flags);
750                         if (smb_fname_dir == NULL) {
751                                 TALLOC_FREE(smb_fname_base);
752                                 TALLOC_FREE(dirname);
753                                 errno = ENOMEM;
754                                 return -1;
755                         }
756                         SMB_VFS_NEXT_RMDIR(handle, smb_fname_dir);
757                         TALLOC_FREE(smb_fname_dir);
758                 }
759                 TALLOC_FREE(dirname);
760         }
761
762         ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
763         TALLOC_FREE(smb_fname_base);
764         return ret;
765 }
766
767 static int streams_depot_rmdir(vfs_handle_struct *handle,
768                                 const struct smb_filename *smb_fname)
769 {
770         struct smb_filename *smb_fname_base = NULL;
771         int ret = -1;
772
773         DEBUG(10, ("streams_depot_rmdir called for %s\n",
774                 smb_fname->base_name));
775
776         /*
777          * We potentially need to delete the per-inode streams directory
778          */
779
780         smb_fname_base = synthetic_smb_fname(talloc_tos(),
781                                 smb_fname->base_name,
782                                 NULL,
783                                 NULL,
784                                 smb_fname->flags);
785         if (smb_fname_base == NULL) {
786                 errno = ENOMEM;
787                 return -1;
788         }
789
790         if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
791                 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
792         } else {
793                 ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
794         }
795
796         if (ret == -1) {
797                 TALLOC_FREE(smb_fname_base);
798                 return -1;
799         }
800
801         /*
802          * We know the rmdir should succeed as the ACL
803          * check is already done in the caller. Remove the
804          * directory *after* the streams.
805          */
806         {
807                 char *dirname = stream_dir(handle, smb_fname_base,
808                                            &smb_fname_base->st, false);
809
810                 if (dirname != NULL) {
811                         struct smb_filename *smb_fname_dir =
812                                 synthetic_smb_fname(talloc_tos(),
813                                                 dirname,
814                                                 NULL,
815                                                 NULL,
816                                                 smb_fname->flags);
817                         if (smb_fname_dir == NULL) {
818                                 TALLOC_FREE(smb_fname_base);
819                                 TALLOC_FREE(dirname);
820                                 errno = ENOMEM;
821                                 return -1;
822                         }
823                         SMB_VFS_NEXT_RMDIR(handle, smb_fname_dir);
824                         TALLOC_FREE(smb_fname_dir);
825                 }
826                 TALLOC_FREE(dirname);
827         }
828
829         ret = SMB_VFS_NEXT_RMDIR(handle, smb_fname_base);
830         TALLOC_FREE(smb_fname_base);
831         return ret;
832 }
833
834 static int streams_depot_renameat(vfs_handle_struct *handle,
835                                 files_struct *srcfsp,
836                                 const struct smb_filename *smb_fname_src,
837                                 files_struct *dstfsp,
838                                 const struct smb_filename *smb_fname_dst)
839 {
840         struct smb_filename *smb_fname_src_stream = NULL;
841         struct smb_filename *smb_fname_dst_stream = NULL;
842         bool src_is_stream, dst_is_stream;
843         NTSTATUS status;
844         int ret = -1;
845
846         DEBUG(10, ("streams_depot_renameat called for %s => %s\n",
847                    smb_fname_str_dbg(smb_fname_src),
848                    smb_fname_str_dbg(smb_fname_dst)));
849
850         src_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
851         dst_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
852
853         if (!src_is_stream && !dst_is_stream) {
854                 return SMB_VFS_NEXT_RENAMEAT(handle,
855                                         srcfsp,
856                                         smb_fname_src,
857                                         dstfsp,
858                                         smb_fname_dst);
859         }
860
861         /* for now don't allow renames from or to the default stream */
862         if (is_ntfs_default_stream_smb_fname(smb_fname_src) ||
863             is_ntfs_default_stream_smb_fname(smb_fname_dst)) {
864                 errno = ENOSYS;
865                 goto done;
866         }
867
868         status = stream_smb_fname(handle, smb_fname_src, &smb_fname_src_stream,
869                                   false);
870         if (!NT_STATUS_IS_OK(status)) {
871                 errno = map_errno_from_nt_status(status);
872                 goto done;
873         }
874
875         status = stream_smb_fname(handle, smb_fname_dst,
876                                   &smb_fname_dst_stream, false);
877         if (!NT_STATUS_IS_OK(status)) {
878                 errno = map_errno_from_nt_status(status);
879                 goto done;
880         }
881
882         ret = SMB_VFS_NEXT_RENAMEAT(handle,
883                                 srcfsp,
884                                 smb_fname_src_stream,
885                                 dstfsp,
886                                 smb_fname_dst_stream);
887
888 done:
889         TALLOC_FREE(smb_fname_src_stream);
890         TALLOC_FREE(smb_fname_dst_stream);
891         return ret;
892 }
893
894 static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
895                            struct stream_struct **streams,
896                            const char *name, off_t size,
897                            off_t alloc_size)
898 {
899         struct stream_struct *tmp;
900
901         tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
902                                    (*num_streams)+1);
903         if (tmp == NULL) {
904                 return false;
905         }
906
907         tmp[*num_streams].name = talloc_strdup(tmp, name);
908         if (tmp[*num_streams].name == NULL) {
909                 return false;
910         }
911
912         tmp[*num_streams].size = size;
913         tmp[*num_streams].alloc_size = alloc_size;
914
915         *streams = tmp;
916         *num_streams += 1;
917         return true;
918 }
919
920 struct streaminfo_state {
921         TALLOC_CTX *mem_ctx;
922         vfs_handle_struct *handle;
923         unsigned int num_streams;
924         struct stream_struct *streams;
925         NTSTATUS status;
926 };
927
928 static bool collect_one_stream(const char *dirname,
929                                const char *dirent,
930                                void *private_data)
931 {
932         struct streaminfo_state *state =
933                 (struct streaminfo_state *)private_data;
934         struct smb_filename *smb_fname = NULL;
935         char *sname = NULL;
936         bool ret;
937
938         sname = talloc_asprintf(talloc_tos(), "%s/%s", dirname, dirent);
939         if (sname == NULL) {
940                 state->status = NT_STATUS_NO_MEMORY;
941                 ret = false;
942                 goto out;
943         }
944
945         smb_fname = synthetic_smb_fname(talloc_tos(), sname, NULL, NULL, 0);
946         if (smb_fname == NULL) {
947                 state->status = NT_STATUS_NO_MEMORY;
948                 ret = false;
949                 goto out;
950         }
951
952         if (SMB_VFS_NEXT_STAT(state->handle, smb_fname) == -1) {
953                 DEBUG(10, ("Could not stat %s: %s\n", sname,
954                            strerror(errno)));
955                 ret = true;
956                 goto out;
957         }
958
959         if (!add_one_stream(state->mem_ctx,
960                             &state->num_streams, &state->streams,
961                             dirent, smb_fname->st.st_ex_size,
962                             SMB_VFS_GET_ALLOC_SIZE(state->handle->conn, NULL,
963                                                    &smb_fname->st))) {
964                 state->status = NT_STATUS_NO_MEMORY;
965                 ret = false;
966                 goto out;
967         }
968
969         ret = true;
970  out:
971         TALLOC_FREE(sname);
972         TALLOC_FREE(smb_fname);
973         return ret;
974 }
975
976 static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
977                                          struct files_struct *fsp,
978                                          const struct smb_filename *smb_fname,
979                                          TALLOC_CTX *mem_ctx,
980                                          unsigned int *pnum_streams,
981                                          struct stream_struct **pstreams)
982 {
983         struct smb_filename *smb_fname_base = NULL;
984         int ret;
985         NTSTATUS status;
986         struct streaminfo_state state;
987
988         smb_fname_base = synthetic_smb_fname(talloc_tos(),
989                                         smb_fname->base_name,
990                                         NULL,
991                                         NULL,
992                                         smb_fname->flags);
993         if (smb_fname_base == NULL) {
994                 return NT_STATUS_NO_MEMORY;
995         }
996
997         if ((fsp != NULL) && (fsp->fh->fd != -1)) {
998                 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &smb_fname_base->st);
999         }
1000         else {
1001                 if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
1002                         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
1003                 } else {
1004                         ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
1005                 }
1006         }
1007
1008         if (ret == -1) {
1009                 status = map_nt_error_from_unix(errno);
1010                 goto out;
1011         }
1012
1013         state.streams = *pstreams;
1014         state.num_streams = *pnum_streams;
1015         state.mem_ctx = mem_ctx;
1016         state.handle = handle;
1017         state.status = NT_STATUS_OK;
1018
1019         if (S_ISLNK(smb_fname_base->st.st_ex_mode)) {
1020                 /*
1021                  * Currently we do't have SMB_VFS_LLISTXATTR
1022                  * inside the VFS which means there's no way
1023                  * to cope with a symlink when lp_posix_pathnames().
1024                  * returns true. For now ignore links.
1025                  * FIXME - by adding SMB_VFS_LLISTXATTR. JRA.
1026                  */
1027                 status = NT_STATUS_OK;
1028         } else {
1029                 status = walk_streams(handle, smb_fname_base, NULL, collect_one_stream,
1030                               &state);
1031         }
1032
1033         if (!NT_STATUS_IS_OK(status)) {
1034                 TALLOC_FREE(state.streams);
1035                 goto out;
1036         }
1037
1038         if (!NT_STATUS_IS_OK(state.status)) {
1039                 TALLOC_FREE(state.streams);
1040                 status = state.status;
1041                 goto out;
1042         }
1043
1044         *pnum_streams = state.num_streams;
1045         *pstreams = state.streams;
1046         status = SMB_VFS_NEXT_STREAMINFO(handle,
1047                                 fsp,
1048                                 smb_fname_base,
1049                                 mem_ctx,
1050                                 pnum_streams,
1051                                 pstreams);
1052
1053  out:
1054         TALLOC_FREE(smb_fname_base);
1055         return status;
1056 }
1057
1058 static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle,
1059                         enum timestamp_set_resolution *p_ts_res)
1060 {
1061         return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS;
1062 }
1063
1064 static struct vfs_fn_pointers vfs_streams_depot_fns = {
1065         .fs_capabilities_fn = streams_depot_fs_capabilities,
1066         .open_fn = streams_depot_open,
1067         .stat_fn = streams_depot_stat,
1068         .lstat_fn = streams_depot_lstat,
1069         .unlink_fn = streams_depot_unlink,
1070         .rmdir_fn = streams_depot_rmdir,
1071         .renameat_fn = streams_depot_renameat,
1072         .streaminfo_fn = streams_depot_streaminfo,
1073 };
1074
1075 static_decl_vfs;
1076 NTSTATUS vfs_streams_depot_init(TALLOC_CTX *ctx)
1077 {
1078         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
1079                                 &vfs_streams_depot_fns);
1080 }