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