Merge branch 'master' of ssh://jht@git.samba.org/data/git/samba
[kai/samba.git] / source3 / modules / vfs_streams_xattr.c
1 /*
2  * Store streams in xattrs
3  *
4  * Copyright (C) Volker Lendecke, 2008
5  *
6  * Partly based on James Peach's Darwin module, which is
7  *
8  * Copyright (C) James Peach 2006-2007
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include "includes.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_VFS
28
29 struct stream_io {
30         char *base;
31         char *xattr_name;
32         void *fsp_name_ptr;
33         files_struct *fsp;
34         vfs_handle_struct *handle;
35 };
36
37 static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
38 {
39         struct MD5Context ctx;
40         unsigned char hash[16];
41         SMB_INO_T result;
42         char *upper_sname;
43
44         DEBUG(10, ("stream_inode called for %lu/%lu [%s]\n",
45                    (unsigned long)sbuf->st_ex_dev,
46                    (unsigned long)sbuf->st_ex_ino, sname));
47
48         upper_sname = talloc_strdup_upper(talloc_tos(), sname);
49         SMB_ASSERT(upper_sname != NULL);
50
51         MD5Init(&ctx);
52         MD5Update(&ctx, (unsigned char *)&(sbuf->st_ex_dev),
53                   sizeof(sbuf->st_ex_dev));
54         MD5Update(&ctx, (unsigned char *)&(sbuf->st_ex_ino),
55                   sizeof(sbuf->st_ex_ino));
56         MD5Update(&ctx, (unsigned char *)upper_sname,
57                   talloc_get_size(upper_sname)-1);
58         MD5Final(hash, &ctx);
59
60         TALLOC_FREE(upper_sname);
61
62         /* Hopefully all the variation is in the lower 4 (or 8) bytes! */
63         memcpy(&result, hash, sizeof(result));
64
65         DEBUG(10, ("stream_inode returns %lu\n", (unsigned long)result));
66
67         return result;
68 }
69
70 static ssize_t get_xattr_size(connection_struct *conn,
71                                 files_struct *fsp,
72                                 const char *fname,
73                                 const char *xattr_name)
74 {
75         NTSTATUS status;
76         struct ea_struct ea;
77         ssize_t result;
78
79         status = get_ea_value(talloc_tos(), conn, fsp, fname,
80                               xattr_name, &ea);
81
82         if (!NT_STATUS_IS_OK(status)) {
83                 return -1;
84         }
85
86         result = ea.value.length-1;
87         TALLOC_FREE(ea.value.data);
88         return result;
89 }
90
91 /**
92  * Given a stream name, populate xattr_name with the xattr name to use for
93  * accessing the stream.
94  */
95 static NTSTATUS streams_xattr_get_name(TALLOC_CTX *ctx,
96                                        const char *stream_name,
97                                        char **xattr_name)
98 {
99         char *stype;
100
101         stype = strchr_m(stream_name + 1, ':');
102
103         *xattr_name = talloc_asprintf(ctx, "%s%s",
104                                       SAMBA_XATTR_DOSSTREAM_PREFIX,
105                                       stream_name + 1);
106         if (*xattr_name == NULL) {
107                 return NT_STATUS_NO_MEMORY;
108         }
109
110         if (stype == NULL) {
111                 /* Append an explicit stream type if one wasn't specified. */
112                 *xattr_name = talloc_asprintf(ctx, "%s:$DATA",
113                                                *xattr_name);
114                 if (*xattr_name == NULL) {
115                         return NT_STATUS_NO_MEMORY;
116                 }
117         } else {
118                 /* Normalize the stream type to upercase. */
119                 strupper_m(strrchr_m(*xattr_name, ':') + 1);
120         }
121
122         DEBUG(10, ("xattr_name: %s, stream_name: %s\n", *xattr_name,
123                    stream_name));
124
125         return NT_STATUS_OK;
126 }
127
128 static bool streams_xattr_recheck(struct stream_io *sio)
129 {
130         NTSTATUS status;
131         char *xattr_name = NULL;
132
133         if (sio->fsp->fsp_name == sio->fsp_name_ptr) {
134                 return true;
135         }
136
137         if (sio->fsp->fsp_name->stream_name == NULL) {
138                 /* how can this happen */
139                 errno = EINVAL;
140                 return false;
141         }
142
143         status = streams_xattr_get_name(talloc_tos(),
144                                         sio->fsp->fsp_name->stream_name,
145                                         &xattr_name);
146         if (!NT_STATUS_IS_OK(status)) {
147                 return false;
148         }
149
150         TALLOC_FREE(sio->xattr_name);
151         TALLOC_FREE(sio->base);
152         sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio->handle, sio->fsp),
153                                         xattr_name);
154         sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio->handle, sio->fsp),
155                                   sio->fsp->fsp_name->base_name);
156         sio->fsp_name_ptr = sio->fsp->fsp_name;
157
158         TALLOC_FREE(xattr_name);
159
160         if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
161                 return false;
162         }
163
164         return true;
165 }
166
167 /**
168  * Helper to stat/lstat the base file of an smb_fname.
169  */
170 static int streams_xattr_stat_base(vfs_handle_struct *handle,
171                                    struct smb_filename *smb_fname,
172                                    bool follow_links)
173 {
174         char *tmp_stream_name;
175         int result;
176
177         tmp_stream_name = smb_fname->stream_name;
178         smb_fname->stream_name = NULL;
179         if (follow_links) {
180                 result = SMB_VFS_NEXT_STAT(handle, smb_fname);
181         } else {
182                 result = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
183         }
184         smb_fname->stream_name = tmp_stream_name;
185         return result;
186 }
187
188 static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
189                                SMB_STRUCT_STAT *sbuf)
190 {
191         struct smb_filename *smb_fname_base = NULL;
192         NTSTATUS status;
193         int ret = -1;
194         struct stream_io *io = (struct stream_io *)
195                 VFS_FETCH_FSP_EXTENSION(handle, fsp);
196
197         DEBUG(10, ("streams_xattr_fstat called for %d\n", fsp->fh->fd));
198
199         if (io == NULL || fsp->base_fsp == NULL) {
200                 return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
201         }
202
203         if (!streams_xattr_recheck(io)) {
204                 return -1;
205         }
206
207         /* Create an smb_filename with stream_name == NULL. */
208         status = create_synthetic_smb_fname(talloc_tos(),
209                                             io->base,
210                                             NULL, NULL,
211                                             &smb_fname_base);
212         if (!NT_STATUS_IS_OK(status)) {
213                 errno = map_errno_from_nt_status(status);
214                 return -1;
215         }
216
217         if (lp_posix_pathnames()) {
218                 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_base);
219         } else {
220                 ret = SMB_VFS_STAT(handle->conn, smb_fname_base);
221         }
222         *sbuf = smb_fname_base->st;
223         TALLOC_FREE(smb_fname_base);
224
225         if (ret == -1) {
226                 return -1;
227         }
228
229         sbuf->st_ex_size = get_xattr_size(handle->conn, fsp->base_fsp,
230                                         io->base, io->xattr_name);
231         if (sbuf->st_ex_size == -1) {
232                 return -1;
233         }
234
235         DEBUG(10, ("sbuf->st_ex_size = %d\n", (int)sbuf->st_ex_size));
236
237         sbuf->st_ex_ino = stream_inode(sbuf, io->xattr_name);
238         sbuf->st_ex_mode &= ~S_IFMT;
239         sbuf->st_ex_mode |= S_IFREG;
240         sbuf->st_ex_blocks = sbuf->st_ex_size % STAT_ST_BLOCKSIZE + 1;
241
242         return 0;
243 }
244
245 static int streams_xattr_stat(vfs_handle_struct *handle,
246                               struct smb_filename *smb_fname)
247 {
248         NTSTATUS status;
249         int result = -1;
250         char *xattr_name = NULL;
251
252         if (!is_ntfs_stream_smb_fname(smb_fname)) {
253                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
254         }
255
256         /* If the default stream is requested, just stat the base file. */
257         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
258                 return streams_xattr_stat_base(handle, smb_fname, true);
259         }
260
261         /* Populate the stat struct with info from the base file. */
262         if (streams_xattr_stat_base(handle, smb_fname, true) == -1) {
263                 return -1;
264         }
265
266         /* Derive the xattr name to lookup. */
267         status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
268                                         &xattr_name);
269         if (!NT_STATUS_IS_OK(status)) {
270                 errno = map_errno_from_nt_status(status);
271                 return -1;
272         }
273
274         /* Augment the base file's stat information before returning. */
275         smb_fname->st.st_ex_size = get_xattr_size(handle->conn, NULL,
276                                                   smb_fname->base_name,
277                                                   xattr_name);
278         if (smb_fname->st.st_ex_size == -1) {
279                 errno = ENOENT;
280                 result = -1;
281                 goto fail;
282         }
283
284         smb_fname->st.st_ex_ino = stream_inode(&smb_fname->st, xattr_name);
285         smb_fname->st.st_ex_mode &= ~S_IFMT;
286         smb_fname->st.st_ex_mode |= S_IFREG;
287         smb_fname->st.st_ex_blocks =
288             smb_fname->st.st_ex_size % STAT_ST_BLOCKSIZE + 1;
289
290         result = 0;
291  fail:
292         TALLOC_FREE(xattr_name);
293         return result;
294 }
295
296 static int streams_xattr_lstat(vfs_handle_struct *handle,
297                                struct smb_filename *smb_fname)
298 {
299         NTSTATUS status;
300         int result = -1;
301         char *xattr_name = NULL;
302
303         if (!is_ntfs_stream_smb_fname(smb_fname)) {
304                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
305         }
306
307                 /* If the default stream is requested, just stat the base file. */
308         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
309                 return streams_xattr_stat_base(handle, smb_fname, false);
310         }
311
312         /* Populate the stat struct with info from the base file. */
313         if (streams_xattr_stat_base(handle, smb_fname, false) == -1) {
314                 return -1;
315         }
316
317         /* Derive the xattr name to lookup. */
318         status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
319                                         &xattr_name);
320         if (!NT_STATUS_IS_OK(status)) {
321                 errno = map_errno_from_nt_status(status);
322                 return -1;
323         }
324
325         /* Augment the base file's stat information before returning. */
326         smb_fname->st.st_ex_size = get_xattr_size(handle->conn, NULL,
327                                                   smb_fname->base_name,
328                                                   xattr_name);
329         if (smb_fname->st.st_ex_size == -1) {
330                 errno = ENOENT;
331                 result = -1;
332                 goto fail;
333         }
334
335         smb_fname->st.st_ex_ino = stream_inode(&smb_fname->st, xattr_name);
336         smb_fname->st.st_ex_mode &= ~S_IFMT;
337         smb_fname->st.st_ex_mode |= S_IFREG;
338         smb_fname->st.st_ex_blocks =
339             smb_fname->st.st_ex_size % STAT_ST_BLOCKSIZE + 1;
340
341         result = 0;
342
343  fail:
344         TALLOC_FREE(xattr_name);
345         return result;
346 }
347
348 static int streams_xattr_open(vfs_handle_struct *handle,
349                               struct smb_filename *smb_fname,
350                               files_struct *fsp, int flags, mode_t mode)
351 {
352         NTSTATUS status;
353         struct smb_filename *smb_fname_base = NULL;
354         struct stream_io *sio;
355         struct ea_struct ea;
356         char *xattr_name = NULL;
357         int baseflags;
358         int hostfd = -1;
359
360         DEBUG(10, ("streams_xattr_open called for %s\n",
361                    smb_fname_str_dbg(smb_fname)));
362
363         if (!is_ntfs_stream_smb_fname(smb_fname)) {
364                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
365         }
366
367         /* If the default stream is requested, just open the base file. */
368         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
369                 char *tmp_stream_name;
370                 int ret;
371
372                 tmp_stream_name = smb_fname->stream_name;
373                 smb_fname->stream_name = NULL;
374
375                 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
376
377                 smb_fname->stream_name = tmp_stream_name;
378
379                 return ret;
380         }
381
382         status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
383                                         &xattr_name);
384         if (!NT_STATUS_IS_OK(status)) {
385                 errno = map_errno_from_nt_status(status);
386                 goto fail;
387         }
388
389         /* Create an smb_filename with stream_name == NULL. */
390         status = create_synthetic_smb_fname(talloc_tos(),
391                                             smb_fname->base_name,
392                                             NULL, NULL,
393                                             &smb_fname_base);
394         if (!NT_STATUS_IS_OK(status)) {
395                 errno = map_errno_from_nt_status(status);
396                 goto fail;
397         }
398
399         /*
400          * We use baseflags to turn off nasty side-effects when opening the
401          * underlying file.
402          */
403         baseflags = flags;
404         baseflags &= ~O_TRUNC;
405         baseflags &= ~O_EXCL;
406         baseflags &= ~O_CREAT;
407
408         hostfd = SMB_VFS_OPEN(handle->conn, smb_fname_base, fsp,
409                               baseflags, mode);
410
411         TALLOC_FREE(smb_fname_base);
412
413         /* It is legit to open a stream on a directory, but the base
414          * fd has to be read-only.
415          */
416         if ((hostfd == -1) && (errno == EISDIR)) {
417                 baseflags &= ~O_ACCMODE;
418                 baseflags |= O_RDONLY;
419                 hostfd = SMB_VFS_OPEN(handle->conn, smb_fname, fsp, baseflags,
420                                       mode);
421         }
422
423         if (hostfd == -1) {
424                 goto fail;
425         }
426
427         status = get_ea_value(talloc_tos(), handle->conn, NULL,
428                               smb_fname->base_name, xattr_name, &ea);
429
430         DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status)));
431
432         if (!NT_STATUS_IS_OK(status)
433             && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
434                 /*
435                  * The base file is not there. This is an error even if we got
436                  * O_CREAT, the higher levels should have created the base
437                  * file for us.
438                  */
439                 DEBUG(10, ("streams_xattr_open: base file %s not around, "
440                            "returning ENOENT\n", smb_fname->base_name));
441                 errno = ENOENT;
442                 goto fail;
443         }
444
445         if (!NT_STATUS_IS_OK(status)) {
446                 /*
447                  * The attribute does not exist
448                  */
449
450                 if (flags & O_CREAT) {
451                         /*
452                          * Darn, xattrs need at least 1 byte
453                          */
454                         char null = '\0';
455
456                         DEBUG(10, ("creating attribute %s on file %s\n",
457                                    xattr_name, smb_fname->base_name));
458
459                         if (fsp->base_fsp->fh->fd != -1) {
460                                 if (SMB_VFS_FSETXATTR(
461                                         fsp->base_fsp, xattr_name,
462                                         &null, sizeof(null),
463                                         flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
464                                         goto fail;
465                                 }
466                         } else {
467                                 if (SMB_VFS_SETXATTR(
468                                         handle->conn, smb_fname->base_name,
469                                         xattr_name, &null, sizeof(null),
470                                         flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
471                                         goto fail;
472                                 }
473                         }
474                 }
475         }
476
477         if (flags & O_TRUNC) {
478                 char null = '\0';
479                 if (fsp->base_fsp->fh->fd != -1) {
480                         if (SMB_VFS_FSETXATTR(
481                                         fsp->base_fsp, xattr_name,
482                                         &null, sizeof(null),
483                                         flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
484                                 goto fail;
485                         }
486                 } else {
487                         if (SMB_VFS_SETXATTR(
488                                         handle->conn, smb_fname->base_name,
489                                         xattr_name, &null, sizeof(null),
490                                         flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
491                                 goto fail;
492                         }
493                 }
494         }
495
496         sio = (struct stream_io *)VFS_ADD_FSP_EXTENSION(handle, fsp,
497                                                         struct stream_io,
498                                                         NULL);
499         if (sio == NULL) {
500                 errno = ENOMEM;
501                 goto fail;
502         }
503
504         sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
505                                         xattr_name);
506         sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
507                                   smb_fname->base_name);
508         sio->fsp_name_ptr = fsp->fsp_name;
509         sio->handle = handle;
510         sio->fsp = fsp;
511
512         if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
513                 errno = ENOMEM;
514                 goto fail;
515         }
516
517         return hostfd;
518
519  fail:
520         if (hostfd >= 0) {
521                 /*
522                  * BUGBUGBUG -- we would need to call fd_close_posix here, but
523                  * we don't have a full fsp yet
524                  */
525                 SMB_VFS_CLOSE(fsp);
526         }
527
528         return -1;
529 }
530
531 static int streams_xattr_unlink(vfs_handle_struct *handle,
532                                 const struct smb_filename *smb_fname)
533 {
534         NTSTATUS status;
535         int ret = -1;
536         char *xattr_name;
537
538         if (!is_ntfs_stream_smb_fname(smb_fname)) {
539                 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
540         }
541
542         /* If the default stream is requested, just open the base file. */
543         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
544                 struct smb_filename *smb_fname_base = NULL;
545
546                 status = copy_smb_filename(talloc_tos(), smb_fname,
547                                             &smb_fname_base);
548                 if (!NT_STATUS_IS_OK(status)) {
549                         errno = map_errno_from_nt_status(status);
550                         return -1;
551                 }
552
553                 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_base);
554
555                 TALLOC_FREE(smb_fname_base);
556                 return ret;
557         }
558
559         status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
560                                         &xattr_name);
561         if (!NT_STATUS_IS_OK(status)) {
562                 errno = map_errno_from_nt_status(status);
563                 goto fail;
564         }
565
566         ret = SMB_VFS_REMOVEXATTR(handle->conn, smb_fname->base_name, xattr_name);
567
568         if ((ret == -1) && (errno == ENOATTR)) {
569                 errno = ENOENT;
570                 goto fail;
571         }
572
573         ret = 0;
574
575  fail:
576         TALLOC_FREE(xattr_name);
577         return ret;
578 }
579
580 static int streams_xattr_rename(vfs_handle_struct *handle,
581                                 const struct smb_filename *smb_fname_src,
582                                 const struct smb_filename *smb_fname_dst)
583 {
584         NTSTATUS status;
585         int ret = -1;
586         char *src_xattr_name = NULL;
587         char *dst_xattr_name = NULL;
588         bool src_is_stream, dst_is_stream;
589         ssize_t oret;
590         ssize_t nret;
591         struct ea_struct ea;
592
593         src_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
594         dst_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
595
596         if (!src_is_stream && !dst_is_stream) {
597                 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
598                                            smb_fname_dst);
599         }
600
601         /* For now don't allow renames from or to the default stream. */
602         if (is_ntfs_default_stream_smb_fname(smb_fname_src) ||
603             is_ntfs_default_stream_smb_fname(smb_fname_dst)) {
604                 errno = ENOSYS;
605                 goto done;
606         }
607
608         /* Don't rename if the streams are identical. */
609         if (StrCaseCmp(smb_fname_src->stream_name,
610                        smb_fname_dst->stream_name) == 0) {
611                 goto done;
612         }
613
614         /* Get the xattr names. */
615         status = streams_xattr_get_name(talloc_tos(),
616                                         smb_fname_src->stream_name,
617                                         &src_xattr_name);
618         if (!NT_STATUS_IS_OK(status)) {
619                 errno = map_errno_from_nt_status(status);
620                 goto fail;
621         }
622         status = streams_xattr_get_name(talloc_tos(),
623                                         smb_fname_dst->stream_name,
624                                         &dst_xattr_name);
625         if (!NT_STATUS_IS_OK(status)) {
626                 errno = map_errno_from_nt_status(status);
627                 goto fail;
628         }
629
630         /* read the old stream */
631         status = get_ea_value(talloc_tos(), handle->conn, NULL,
632                               smb_fname_src->base_name, src_xattr_name, &ea);
633         if (!NT_STATUS_IS_OK(status)) {
634                 errno = ENOENT;
635                 goto fail;
636         }
637
638         /* (over)write the new stream */
639         nret = SMB_VFS_SETXATTR(handle->conn, smb_fname_src->base_name,
640                                 dst_xattr_name, ea.value.data, ea.value.length,
641                                 0);
642         if (nret < 0) {
643                 if (errno == ENOATTR) {
644                         errno = ENOENT;
645                 }
646                 goto fail;
647         }
648
649         /* remove the old stream */
650         oret = SMB_VFS_REMOVEXATTR(handle->conn, smb_fname_src->base_name,
651                                    src_xattr_name);
652         if (oret < 0) {
653                 if (errno == ENOATTR) {
654                         errno = ENOENT;
655                 }
656                 goto fail;
657         }
658
659  done:
660         errno = 0;
661         ret = 0;
662  fail:
663         TALLOC_FREE(src_xattr_name);
664         TALLOC_FREE(dst_xattr_name);
665         return ret;
666 }
667
668 static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
669                                    const char *fname,
670                                    bool (*fn)(struct ea_struct *ea,
671                                               void *private_data),
672                                    void *private_data)
673 {
674         NTSTATUS status;
675         char **names;
676         size_t i, num_names;
677         size_t prefix_len = strlen(SAMBA_XATTR_DOSSTREAM_PREFIX);
678
679         status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
680                                         &names, &num_names);
681         if (!NT_STATUS_IS_OK(status)) {
682                 return status;
683         }
684
685         for (i=0; i<num_names; i++) {
686                 struct ea_struct ea;
687
688                 if (strncmp(names[i], SAMBA_XATTR_DOSSTREAM_PREFIX,
689                             prefix_len) != 0) {
690                         continue;
691                 }
692
693                 status = get_ea_value(names, conn, fsp, fname, names[i], &ea);
694                 if (!NT_STATUS_IS_OK(status)) {
695                         DEBUG(10, ("Could not get ea %s for file %s: %s\n",
696                                    names[i], fname, nt_errstr(status)));
697                         continue;
698                 }
699
700                 ea.name = talloc_asprintf(ea.value.data, ":%s",
701                                           names[i] + prefix_len);
702                 if (ea.name == NULL) {
703                         DEBUG(0, ("talloc failed\n"));
704                         continue;
705                 }
706
707                 if (!fn(&ea, private_data)) {
708                         TALLOC_FREE(ea.value.data);
709                         return NT_STATUS_OK;
710                 }
711
712                 TALLOC_FREE(ea.value.data);
713         }
714
715         TALLOC_FREE(names);
716         return NT_STATUS_OK;
717 }
718
719 static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
720                            struct stream_struct **streams,
721                            const char *name, SMB_OFF_T size,
722                            SMB_OFF_T alloc_size)
723 {
724         struct stream_struct *tmp;
725
726         tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct,
727                                    (*num_streams)+1);
728         if (tmp == NULL) {
729                 return false;
730         }
731
732         tmp[*num_streams].name = talloc_strdup(tmp, name);
733         if (tmp[*num_streams].name == NULL) {
734                 return false;
735         }
736
737         tmp[*num_streams].size = size;
738         tmp[*num_streams].alloc_size = alloc_size;
739
740         *streams = tmp;
741         *num_streams += 1;
742         return true;
743 }
744
745 struct streaminfo_state {
746         TALLOC_CTX *mem_ctx;
747         vfs_handle_struct *handle;
748         unsigned int num_streams;
749         struct stream_struct *streams;
750         NTSTATUS status;
751 };
752
753 static bool collect_one_stream(struct ea_struct *ea, void *private_data)
754 {
755         struct streaminfo_state *state =
756                 (struct streaminfo_state *)private_data;
757
758         if (!add_one_stream(state->mem_ctx,
759                             &state->num_streams, &state->streams,
760                             ea->name, ea->value.length-1,
761                             smb_roundup(state->handle->conn,
762                                         ea->value.length-1))) {
763                 state->status = NT_STATUS_NO_MEMORY;
764                 return false;
765         }
766
767         return true;
768 }
769
770 static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle,
771                                          struct files_struct *fsp,
772                                          const char *fname,
773                                          TALLOC_CTX *mem_ctx,
774                                          unsigned int *pnum_streams,
775                                          struct stream_struct **pstreams)
776 {
777         SMB_STRUCT_STAT sbuf;
778         int ret;
779         NTSTATUS status;
780         struct streaminfo_state state;
781
782         if ((fsp != NULL) && (fsp->fh->fd != -1)) {
783                 ret = SMB_VFS_FSTAT(fsp, &sbuf);
784         }
785         else {
786                 struct smb_filename *smb_fname = NULL;
787                 status = create_synthetic_smb_fname(talloc_tos(), fname, NULL,
788                                                     NULL, &smb_fname);
789                 if (!NT_STATUS_IS_OK(status)) {
790                         return status;
791                 }
792                 if (lp_posix_pathnames()) {
793                         ret = SMB_VFS_LSTAT(handle->conn, smb_fname);
794                 } else {
795                         ret = SMB_VFS_STAT(handle->conn, smb_fname);
796                 }
797                 sbuf = smb_fname->st;
798                 TALLOC_FREE(smb_fname);
799         }
800
801         if (ret == -1) {
802                 return map_nt_error_from_unix(errno);
803         }
804
805         state.streams = NULL;
806         state.num_streams = 0;
807
808         if (!S_ISDIR(sbuf.st_ex_mode)) {
809                 if (!add_one_stream(mem_ctx,
810                                     &state.num_streams, &state.streams,
811                                     "::$DATA", sbuf.st_ex_size,
812                                     SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp,
813                                                            &sbuf))) {
814                         return NT_STATUS_NO_MEMORY;
815                 }
816         }
817
818         state.mem_ctx = mem_ctx;
819         state.handle = handle;
820         state.status = NT_STATUS_OK;
821
822         status = walk_xattr_streams(handle->conn, fsp, fname,
823                                     collect_one_stream, &state);
824
825         if (!NT_STATUS_IS_OK(status)) {
826                 TALLOC_FREE(state.streams);
827                 return status;
828         }
829
830         if (!NT_STATUS_IS_OK(state.status)) {
831                 TALLOC_FREE(state.streams);
832                 return state.status;
833         }
834
835         *pnum_streams = state.num_streams;
836         *pstreams = state.streams;
837         return NT_STATUS_OK;
838 }
839
840 static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle)
841 {
842         return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS;
843 }
844
845 static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
846                                     files_struct *fsp, const void *data,
847                                     size_t n, SMB_OFF_T offset)
848 {
849         struct stream_io *sio =
850                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
851         struct ea_struct ea;
852         NTSTATUS status;
853         int ret;
854
855         DEBUG(10, ("streams_xattr_pwrite called for %d bytes\n", (int)n));
856
857         if (sio == NULL) {
858                 return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
859         }
860
861         if (!streams_xattr_recheck(sio)) {
862                 return -1;
863         }
864
865         status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
866                               sio->base, sio->xattr_name, &ea);
867         if (!NT_STATUS_IS_OK(status)) {
868                 return -1;
869         }
870
871         if ((offset + n) > ea.value.length-1) {
872                 uint8 *tmp;
873
874                 tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
875                                            offset + n + 1);
876
877                 if (tmp == NULL) {
878                         TALLOC_FREE(ea.value.data);
879                         errno = ENOMEM;
880                         return -1;
881                 }
882                 ea.value.data = tmp;
883                 ea.value.length = offset + n + 1;
884                 ea.value.data[offset+n] = 0;
885         }
886
887         memcpy(ea.value.data + offset, data, n);
888
889         if (fsp->base_fsp->fh->fd != -1) {
890                 ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
891                                 sio->xattr_name,
892                                 ea.value.data, ea.value.length, 0);
893         } else {
894                 ret = SMB_VFS_SETXATTR(fsp->conn,
895                                        fsp->base_fsp->fsp_name->base_name,
896                                 sio->xattr_name,
897                                 ea.value.data, ea.value.length, 0);
898         }
899         TALLOC_FREE(ea.value.data);
900
901         if (ret == -1) {
902                 return -1;
903         }
904
905         return n;
906 }
907
908 static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
909                                    files_struct *fsp, void *data,
910                                    size_t n, SMB_OFF_T offset)
911 {
912         struct stream_io *sio =
913                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
914         struct ea_struct ea;
915         NTSTATUS status;
916         size_t length, overlap;
917
918         if (sio == NULL) {
919                 return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
920         }
921
922         if (!streams_xattr_recheck(sio)) {
923                 return -1;
924         }
925
926         status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
927                               sio->base, sio->xattr_name, &ea);
928         if (!NT_STATUS_IS_OK(status)) {
929                 return -1;
930         }
931
932         length = ea.value.length-1;
933
934         /* Attempt to read past EOF. */
935         if (length <= offset) {
936                 errno = EINVAL;
937                 return -1;
938         }
939
940         overlap = (offset + n) > length ? (length - offset) : n;
941         memcpy(data, ea.value.data + offset, overlap);
942
943         TALLOC_FREE(ea.value.data);
944         return overlap;
945 }
946
947 static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
948                                         struct files_struct *fsp,
949                                         SMB_OFF_T offset)
950 {
951         int ret;
952         uint8 *tmp;
953         struct ea_struct ea;
954         NTSTATUS status;
955         struct stream_io *sio =
956                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
957
958         DEBUG(10, ("streams_xattr_ftruncate called for file %s offset %.0f\n",
959                    fsp_str_dbg(fsp), (double)offset));
960
961         if (sio == NULL) {
962                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
963         }
964
965         if (!streams_xattr_recheck(sio)) {
966                 return -1;
967         }
968
969         status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
970                               sio->base, sio->xattr_name, &ea);
971         if (!NT_STATUS_IS_OK(status)) {
972                 return -1;
973         }
974
975         tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
976                                    offset + 1);
977
978         if (tmp == NULL) {
979                 TALLOC_FREE(ea.value.data);
980                 errno = ENOMEM;
981                 return -1;
982         }
983
984         /* Did we expand ? */
985         if (ea.value.length < offset + 1) {
986                 memset(&tmp[ea.value.length], '\0',
987                         offset + 1 - ea.value.length);
988         }
989
990         ea.value.data = tmp;
991         ea.value.length = offset + 1;
992         ea.value.data[offset] = 0;
993
994         if (fsp->base_fsp->fh->fd != -1) {
995                 ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
996                                 sio->xattr_name,
997                                 ea.value.data, ea.value.length, 0);
998         } else {
999                 ret = SMB_VFS_SETXATTR(fsp->conn,
1000                                        fsp->base_fsp->fsp_name->base_name,
1001                                 sio->xattr_name,
1002                                 ea.value.data, ea.value.length, 0);
1003         }
1004
1005         TALLOC_FREE(ea.value.data);
1006
1007         if (ret == -1) {
1008                 return -1;
1009         }
1010
1011         return 0;
1012 }
1013
1014 /* VFS operations structure */
1015
1016 static vfs_op_tuple streams_xattr_ops[] = {
1017         {SMB_VFS_OP(streams_xattr_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
1018          SMB_VFS_LAYER_TRANSPARENT},
1019         {SMB_VFS_OP(streams_xattr_open), SMB_VFS_OP_OPEN,
1020          SMB_VFS_LAYER_TRANSPARENT},
1021         {SMB_VFS_OP(streams_xattr_stat), SMB_VFS_OP_STAT,
1022          SMB_VFS_LAYER_TRANSPARENT},
1023         {SMB_VFS_OP(streams_xattr_fstat), SMB_VFS_OP_FSTAT,
1024          SMB_VFS_LAYER_TRANSPARENT},
1025         {SMB_VFS_OP(streams_xattr_lstat), SMB_VFS_OP_LSTAT,
1026          SMB_VFS_LAYER_TRANSPARENT},
1027         {SMB_VFS_OP(streams_xattr_pread), SMB_VFS_OP_PREAD,
1028          SMB_VFS_LAYER_TRANSPARENT},
1029         {SMB_VFS_OP(streams_xattr_pwrite), SMB_VFS_OP_PWRITE,
1030          SMB_VFS_LAYER_TRANSPARENT},
1031         {SMB_VFS_OP(streams_xattr_unlink), SMB_VFS_OP_UNLINK,
1032          SMB_VFS_LAYER_TRANSPARENT},
1033         {SMB_VFS_OP(streams_xattr_rename), SMB_VFS_OP_RENAME,
1034          SMB_VFS_LAYER_TRANSPARENT},
1035         {SMB_VFS_OP(streams_xattr_ftruncate),  SMB_VFS_OP_FTRUNCATE,
1036          SMB_VFS_LAYER_TRANSPARENT},
1037         {SMB_VFS_OP(streams_xattr_streaminfo), SMB_VFS_OP_STREAMINFO,
1038          SMB_VFS_LAYER_OPAQUE},
1039         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
1040 };
1041
1042 NTSTATUS vfs_streams_xattr_init(void);
1043 NTSTATUS vfs_streams_xattr_init(void)
1044 {
1045         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_xattr",
1046                                 streams_xattr_ops);
1047 }