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