s3: Plumb smb_filename through SMB_VFS_RENAME
[metze/samba/wip.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 *base = NULL;
132         char *sname = NULL;
133         char *xattr_name = NULL;
134
135         if (sio->fsp->fsp_name == sio->fsp_name_ptr) {
136                 return true;
137         }
138
139         status = split_ntfs_stream_name(talloc_tos(), sio->fsp->fsp_name,
140                                         &base, &sname);
141         if (!NT_STATUS_IS_OK(status)) {
142                 return false;
143         }
144
145         if (sname == NULL) {
146                 /* how can this happen */
147                 errno = EINVAL;
148                 return false;
149         }
150
151         xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
152                                      SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
153         if (xattr_name == NULL) {
154                 return false;
155         }
156
157         TALLOC_FREE(sio->xattr_name);
158         TALLOC_FREE(sio->base);
159         sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio->handle, sio->fsp),
160                                         xattr_name);
161         sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio->handle, sio->fsp),
162                                   base);
163         sio->fsp_name_ptr = sio->fsp->fsp_name;
164
165         if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
166                 return false;
167         }
168
169         return true;
170 }
171
172 /**
173  * Helper to stat/lstat the base file of an smb_fname.
174  */
175 static int streams_xattr_stat_base(vfs_handle_struct *handle,
176                                    struct smb_filename *smb_fname,
177                                    bool follow_links)
178 {
179         char *tmp_stream_name;
180         int result;
181
182         tmp_stream_name = smb_fname->stream_name;
183         smb_fname->stream_name = NULL;
184         if (follow_links) {
185                 result = SMB_VFS_NEXT_STAT(handle, smb_fname);
186         } else {
187                 result = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
188         }
189         smb_fname->stream_name = tmp_stream_name;
190         return result;
191 }
192
193 static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
194                                SMB_STRUCT_STAT *sbuf)
195 {
196         struct smb_filename *smb_fname_base = NULL;
197         NTSTATUS status;
198         int ret = -1;
199         struct stream_io *io = (struct stream_io *)
200                 VFS_FETCH_FSP_EXTENSION(handle, fsp);
201
202         DEBUG(10, ("streams_xattr_fstat called for %d\n", fsp->fh->fd));
203
204         if (io == NULL || fsp->base_fsp == NULL) {
205                 return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
206         }
207
208         if (!streams_xattr_recheck(io)) {
209                 return -1;
210         }
211
212         /* Create an smb_filename with stream_name == NULL. */
213         status = create_synthetic_smb_fname(talloc_tos(),
214                                             io->base,
215                                             NULL, NULL,
216                                             &smb_fname_base);
217         if (!NT_STATUS_IS_OK(status)) {
218                 errno = map_errno_from_nt_status(status);
219                 return -1;
220         }
221
222         if (lp_posix_pathnames()) {
223                 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_base);
224         } else {
225                 ret = SMB_VFS_STAT(handle->conn, smb_fname_base);
226         }
227         *sbuf = smb_fname_base->st;
228         TALLOC_FREE(smb_fname_base);
229
230         if (ret == -1) {
231                 return -1;
232         }
233
234         sbuf->st_ex_size = get_xattr_size(handle->conn, fsp->base_fsp,
235                                         io->base, io->xattr_name);
236         if (sbuf->st_ex_size == -1) {
237                 return -1;
238         }
239
240         DEBUG(10, ("sbuf->st_ex_size = %d\n", (int)sbuf->st_ex_size));
241
242         sbuf->st_ex_ino = stream_inode(sbuf, io->xattr_name);
243         sbuf->st_ex_mode &= ~S_IFMT;
244         sbuf->st_ex_mode |= S_IFREG;
245         sbuf->st_ex_blocks = sbuf->st_ex_size % STAT_ST_BLOCKSIZE + 1;
246
247         return 0;
248 }
249
250 static int streams_xattr_stat(vfs_handle_struct *handle,
251                               struct smb_filename *smb_fname)
252 {
253         NTSTATUS status;
254         int result = -1;
255         char *xattr_name = NULL;
256
257         if (!is_ntfs_stream_smb_fname(smb_fname)) {
258                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
259         }
260
261         /* If the default stream is requested, just stat the base file. */
262         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
263                 return streams_xattr_stat_base(handle, smb_fname, true);
264         }
265
266         /* Populate the stat struct with info from the base file. */
267         if (streams_xattr_stat_base(handle, smb_fname, true) == -1) {
268                 return -1;
269         }
270
271         /* Derive the xattr name to lookup. */
272         status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
273                                         &xattr_name);
274         if (!NT_STATUS_IS_OK(status)) {
275                 errno = map_errno_from_nt_status(status);
276                 return -1;
277         }
278
279         /* Augment the base file's stat information before returning. */
280         smb_fname->st.st_ex_size = get_xattr_size(handle->conn, NULL,
281                                                   smb_fname->base_name,
282                                                   xattr_name);
283         if (smb_fname->st.st_ex_size == -1) {
284                 errno = ENOENT;
285                 result = -1;
286                 goto fail;
287         }
288
289         smb_fname->st.st_ex_ino = stream_inode(&smb_fname->st, xattr_name);
290         smb_fname->st.st_ex_mode &= ~S_IFMT;
291         smb_fname->st.st_ex_mode |= S_IFREG;
292         smb_fname->st.st_ex_blocks =
293             smb_fname->st.st_ex_size % STAT_ST_BLOCKSIZE + 1;
294
295         result = 0;
296  fail:
297         TALLOC_FREE(xattr_name);
298         return result;
299 }
300
301 static int streams_xattr_lstat(vfs_handle_struct *handle,
302                                struct smb_filename *smb_fname)
303 {
304         NTSTATUS status;
305         int result = -1;
306         char *xattr_name = NULL;
307
308         if (!is_ntfs_stream_smb_fname(smb_fname)) {
309                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
310         }
311
312                 /* If the default stream is requested, just stat the base file. */
313         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
314                 return streams_xattr_stat_base(handle, smb_fname, false);
315         }
316
317         /* Populate the stat struct with info from the base file. */
318         if (streams_xattr_stat_base(handle, smb_fname, false) == -1) {
319                 return -1;
320         }
321
322         /* Derive the xattr name to lookup. */
323         status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
324                                         &xattr_name);
325         if (!NT_STATUS_IS_OK(status)) {
326                 errno = map_errno_from_nt_status(status);
327                 return -1;
328         }
329
330         /* Augment the base file's stat information before returning. */
331         smb_fname->st.st_ex_size = get_xattr_size(handle->conn, NULL,
332                                                   smb_fname->base_name,
333                                                   xattr_name);
334         if (smb_fname->st.st_ex_size == -1) {
335                 errno = ENOENT;
336                 result = -1;
337                 goto fail;
338         }
339
340         smb_fname->st.st_ex_ino = stream_inode(&smb_fname->st, xattr_name);
341         smb_fname->st.st_ex_mode &= ~S_IFMT;
342         smb_fname->st.st_ex_mode |= S_IFREG;
343         smb_fname->st.st_ex_blocks =
344             smb_fname->st.st_ex_size % STAT_ST_BLOCKSIZE + 1;
345
346         result = 0;
347
348  fail:
349         TALLOC_FREE(xattr_name);
350         return result;
351 }
352
353 static int streams_xattr_open(vfs_handle_struct *handle,
354                               struct smb_filename *smb_fname,
355                               files_struct *fsp, int flags, mode_t mode)
356 {
357         NTSTATUS status;
358         struct smb_filename *smb_fname_base = NULL;
359         struct stream_io *sio;
360         struct ea_struct ea;
361         char *xattr_name = NULL;
362         int baseflags;
363         int hostfd = -1;
364
365         DEBUG(10, ("streams_xattr_open called for %s\n",
366                    smb_fname_str_dbg(smb_fname)));
367
368         if (!is_ntfs_stream_smb_fname(smb_fname)) {
369                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
370         }
371
372         /* If the default stream is requested, just open the base file. */
373         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
374                 char *tmp_stream_name;
375                 int ret;
376
377                 tmp_stream_name = smb_fname->stream_name;
378                 smb_fname->stream_name = NULL;
379
380                 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
381
382                 smb_fname->stream_name = tmp_stream_name;
383
384                 return ret;
385         }
386
387         status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
388                                         &xattr_name);
389         if (!NT_STATUS_IS_OK(status)) {
390                 errno = map_errno_from_nt_status(status);
391                 goto fail;
392         }
393
394         /* Create an smb_filename with stream_name == NULL. */
395         status = create_synthetic_smb_fname(talloc_tos(),
396                                             smb_fname->base_name,
397                                             NULL, NULL,
398                                             &smb_fname_base);
399         if (!NT_STATUS_IS_OK(status)) {
400                 errno = map_errno_from_nt_status(status);
401                 goto fail;
402         }
403
404         /*
405          * We use baseflags to turn off nasty side-effects when opening the
406          * underlying file.
407          */
408         baseflags = flags;
409         baseflags &= ~O_TRUNC;
410         baseflags &= ~O_EXCL;
411         baseflags &= ~O_CREAT;
412
413         hostfd = SMB_VFS_OPEN(handle->conn, smb_fname_base, fsp,
414                               baseflags, mode);
415
416         TALLOC_FREE(smb_fname_base);
417
418         /* It is legit to open a stream on a directory, but the base
419          * fd has to be read-only.
420          */
421         if ((hostfd == -1) && (errno == EISDIR)) {
422                 baseflags &= ~O_ACCMODE;
423                 baseflags |= O_RDONLY;
424                 hostfd = SMB_VFS_OPEN(handle->conn, smb_fname, fsp, baseflags,
425                                       mode);
426         }
427
428         if (hostfd == -1) {
429                 goto fail;
430         }
431
432         status = get_ea_value(talloc_tos(), handle->conn, NULL,
433                               smb_fname->base_name, xattr_name, &ea);
434
435         DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status)));
436
437         if (!NT_STATUS_IS_OK(status)
438             && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
439                 /*
440                  * The base file is not there. This is an error even if we got
441                  * O_CREAT, the higher levels should have created the base
442                  * file for us.
443                  */
444                 DEBUG(10, ("streams_xattr_open: base file %s not around, "
445                            "returning ENOENT\n", smb_fname->base_name));
446                 errno = ENOENT;
447                 goto fail;
448         }
449
450         if (!NT_STATUS_IS_OK(status)) {
451                 /*
452                  * The attribute does not exist
453                  */
454
455                 if (flags & O_CREAT) {
456                         /*
457                          * Darn, xattrs need at least 1 byte
458                          */
459                         char null = '\0';
460
461                         DEBUG(10, ("creating attribute %s on file %s\n",
462                                    xattr_name, smb_fname->base_name));
463
464                         if (fsp->base_fsp->fh->fd != -1) {
465                                 if (SMB_VFS_FSETXATTR(
466                                         fsp->base_fsp, xattr_name,
467                                         &null, sizeof(null),
468                                         flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
469                                         goto fail;
470                                 }
471                         } else {
472                                 if (SMB_VFS_SETXATTR(
473                                         handle->conn, smb_fname->base_name,
474                                         xattr_name, &null, sizeof(null),
475                                         flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
476                                         goto fail;
477                                 }
478                         }
479                 }
480         }
481
482         if (flags & O_TRUNC) {
483                 char null = '\0';
484                 if (fsp->base_fsp->fh->fd != -1) {
485                         if (SMB_VFS_FSETXATTR(
486                                         fsp->base_fsp, xattr_name,
487                                         &null, sizeof(null),
488                                         flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
489                                 goto fail;
490                         }
491                 } else {
492                         if (SMB_VFS_SETXATTR(
493                                         handle->conn, smb_fname->base_name,
494                                         xattr_name, &null, sizeof(null),
495                                         flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
496                                 goto fail;
497                         }
498                 }
499         }
500
501         sio = (struct stream_io *)VFS_ADD_FSP_EXTENSION(handle, fsp,
502                                                         struct stream_io,
503                                                         NULL);
504         if (sio == NULL) {
505                 errno = ENOMEM;
506                 goto fail;
507         }
508
509         sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
510                                         xattr_name);
511         sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
512                                   smb_fname->base_name);
513         sio->fsp_name_ptr = fsp->fsp_name;
514         sio->handle = handle;
515         sio->fsp = fsp;
516
517         if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
518                 errno = ENOMEM;
519                 goto fail;
520         }
521
522         return hostfd;
523
524  fail:
525         if (hostfd >= 0) {
526                 /*
527                  * BUGBUGBUG -- we would need to call fd_close_posix here, but
528                  * we don't have a full fsp yet
529                  */
530                 SMB_VFS_CLOSE(fsp);
531         }
532
533         return -1;
534 }
535
536 static int streams_xattr_unlink(vfs_handle_struct *handle,  const char *fname)
537 {
538         NTSTATUS status;
539         char *base = NULL;
540         char *sname = NULL;
541         int ret = -1;
542         char *xattr_name;
543
544         if (!is_ntfs_stream_name(fname)) {
545                 return SMB_VFS_NEXT_UNLINK(handle, fname);
546         }
547
548         status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
549         if (!NT_STATUS_IS_OK(status)) {
550                 errno = EINVAL;
551                 goto fail;
552         }
553
554         if (sname == NULL){
555                 return SMB_VFS_NEXT_UNLINK(handle, base);
556         }
557
558         xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
559                                      SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
560         if (xattr_name == NULL) {
561                 errno = ENOMEM;
562                 goto fail;
563         }
564
565         ret = SMB_VFS_REMOVEXATTR(handle->conn, base, xattr_name);
566
567         if ((ret == -1) && (errno == ENOATTR)) {
568                 errno = ENOENT;
569                 goto fail;
570         }
571
572         ret = 0;
573
574  fail:
575         TALLOC_FREE(base);
576         TALLOC_FREE(sname);
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                 if (is_ntfs_stream_name(fsp->fsp_name)) {
784                         return NT_STATUS_INVALID_PARAMETER;
785                 }
786                 ret = SMB_VFS_FSTAT(fsp, &sbuf);
787         }
788         else {
789                 if (is_ntfs_stream_name(fname)) {
790                         return NT_STATUS_INVALID_PARAMETER;
791                 }
792                 if (lp_posix_pathnames()) {
793                         ret = vfs_lstat_smb_fname(handle->conn, fname, &sbuf);
794                 } else {
795                         ret = vfs_stat_smb_fname(handle->conn, fname, &sbuf);
796                 }
797         }
798
799         if (ret == -1) {
800                 return map_nt_error_from_unix(errno);
801         }
802
803         state.streams = NULL;
804         state.num_streams = 0;
805
806         if (!S_ISDIR(sbuf.st_ex_mode)) {
807                 if (!add_one_stream(mem_ctx,
808                                     &state.num_streams, &state.streams,
809                                     "::$DATA", sbuf.st_ex_size,
810                                     SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp,
811                                                            &sbuf))) {
812                         return NT_STATUS_NO_MEMORY;
813                 }
814         }
815
816         state.mem_ctx = mem_ctx;
817         state.handle = handle;
818         state.status = NT_STATUS_OK;
819
820         status = walk_xattr_streams(handle->conn, fsp, fname,
821                                     collect_one_stream, &state);
822
823         if (!NT_STATUS_IS_OK(status)) {
824                 TALLOC_FREE(state.streams);
825                 return status;
826         }
827
828         if (!NT_STATUS_IS_OK(state.status)) {
829                 TALLOC_FREE(state.streams);
830                 return state.status;
831         }
832
833         *pnum_streams = state.num_streams;
834         *pstreams = state.streams;
835         return NT_STATUS_OK;
836 }
837
838 static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle)
839 {
840         return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS;
841 }
842
843 static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
844                                     files_struct *fsp, const void *data,
845                                     size_t n, SMB_OFF_T offset)
846 {
847         struct stream_io *sio =
848                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
849         struct ea_struct ea;
850         NTSTATUS status;
851         int ret;
852
853         DEBUG(10, ("streams_xattr_pwrite called for %d bytes\n", (int)n));
854
855         if (sio == NULL) {
856                 return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
857         }
858
859         if (!streams_xattr_recheck(sio)) {
860                 return -1;
861         }
862
863         status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
864                               sio->base, sio->xattr_name, &ea);
865         if (!NT_STATUS_IS_OK(status)) {
866                 return -1;
867         }
868
869         if ((offset + n) > ea.value.length-1) {
870                 uint8 *tmp;
871
872                 tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
873                                            offset + n + 1);
874
875                 if (tmp == NULL) {
876                         TALLOC_FREE(ea.value.data);
877                         errno = ENOMEM;
878                         return -1;
879                 }
880                 ea.value.data = tmp;
881                 ea.value.length = offset + n + 1;
882                 ea.value.data[offset+n] = 0;
883         }
884
885         memcpy(ea.value.data + offset, data, n);
886
887         if (fsp->base_fsp->fh->fd != -1) {
888                 ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
889                                 sio->xattr_name,
890                                 ea.value.data, ea.value.length, 0);
891         } else {
892                 ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name,
893                                 sio->xattr_name,
894                                 ea.value.data, ea.value.length, 0);
895         }
896         TALLOC_FREE(ea.value.data);
897
898         if (ret == -1) {
899                 return -1;
900         }
901
902         return n;
903 }
904
905 static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
906                                    files_struct *fsp, void *data,
907                                    size_t n, SMB_OFF_T offset)
908 {
909         struct stream_io *sio =
910                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
911         struct ea_struct ea;
912         NTSTATUS status;
913         size_t length, overlap;
914
915         if (sio == NULL) {
916                 return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
917         }
918
919         if (!streams_xattr_recheck(sio)) {
920                 return -1;
921         }
922
923         status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
924                               sio->base, sio->xattr_name, &ea);
925         if (!NT_STATUS_IS_OK(status)) {
926                 return -1;
927         }
928
929         length = ea.value.length-1;
930
931         /* Attempt to read past EOF. */
932         if (length <= offset) {
933                 errno = EINVAL;
934                 return -1;
935         }
936
937         overlap = (offset + n) > length ? (length - offset) : n;
938         memcpy(data, ea.value.data + offset, overlap);
939
940         TALLOC_FREE(ea.value.data);
941         return overlap;
942 }
943
944 static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
945                                         struct files_struct *fsp,
946                                         SMB_OFF_T offset)
947 {
948         int ret;
949         uint8 *tmp;
950         struct ea_struct ea;
951         NTSTATUS status;
952         struct stream_io *sio =
953                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
954
955         DEBUG(10, ("streams_xattr_ftruncate called for file %s offset %.0f\n",
956                 fsp->fsp_name,
957                 (double)offset ));
958
959         if (sio == NULL) {
960                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
961         }
962
963         if (!streams_xattr_recheck(sio)) {
964                 return -1;
965         }
966
967         status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
968                               sio->base, sio->xattr_name, &ea);
969         if (!NT_STATUS_IS_OK(status)) {
970                 return -1;
971         }
972
973         tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
974                                    offset + 1);
975
976         if (tmp == NULL) {
977                 TALLOC_FREE(ea.value.data);
978                 errno = ENOMEM;
979                 return -1;
980         }
981
982         /* Did we expand ? */
983         if (ea.value.length < offset + 1) {
984                 memset(&tmp[ea.value.length], '\0',
985                         offset + 1 - ea.value.length);
986         }
987
988         ea.value.data = tmp;
989         ea.value.length = offset + 1;
990         ea.value.data[offset] = 0;
991
992         if (fsp->base_fsp->fh->fd != -1) {
993                 ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
994                                 sio->xattr_name,
995                                 ea.value.data, ea.value.length, 0);
996         } else {
997                 ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name,
998                                 sio->xattr_name,
999                                 ea.value.data, ea.value.length, 0);
1000         }
1001
1002         TALLOC_FREE(ea.value.data);
1003
1004         if (ret == -1) {
1005                 return -1;
1006         }
1007
1008         return 0;
1009 }
1010
1011 /* VFS operations structure */
1012
1013 static vfs_op_tuple streams_xattr_ops[] = {
1014         {SMB_VFS_OP(streams_xattr_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
1015          SMB_VFS_LAYER_TRANSPARENT},
1016         {SMB_VFS_OP(streams_xattr_open), SMB_VFS_OP_OPEN,
1017          SMB_VFS_LAYER_TRANSPARENT},
1018         {SMB_VFS_OP(streams_xattr_stat), SMB_VFS_OP_STAT,
1019          SMB_VFS_LAYER_TRANSPARENT},
1020         {SMB_VFS_OP(streams_xattr_fstat), SMB_VFS_OP_FSTAT,
1021          SMB_VFS_LAYER_TRANSPARENT},
1022         {SMB_VFS_OP(streams_xattr_lstat), SMB_VFS_OP_LSTAT,
1023          SMB_VFS_LAYER_TRANSPARENT},
1024         {SMB_VFS_OP(streams_xattr_pread), SMB_VFS_OP_PREAD,
1025          SMB_VFS_LAYER_TRANSPARENT},
1026         {SMB_VFS_OP(streams_xattr_pwrite), SMB_VFS_OP_PWRITE,
1027          SMB_VFS_LAYER_TRANSPARENT},
1028         {SMB_VFS_OP(streams_xattr_unlink), SMB_VFS_OP_UNLINK,
1029          SMB_VFS_LAYER_TRANSPARENT},
1030         {SMB_VFS_OP(streams_xattr_rename), SMB_VFS_OP_RENAME,
1031          SMB_VFS_LAYER_TRANSPARENT},
1032         {SMB_VFS_OP(streams_xattr_ftruncate),  SMB_VFS_OP_FTRUNCATE,
1033          SMB_VFS_LAYER_TRANSPARENT},
1034         {SMB_VFS_OP(streams_xattr_streaminfo), SMB_VFS_OP_STREAMINFO,
1035          SMB_VFS_LAYER_OPAQUE},
1036         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
1037 };
1038
1039 NTSTATUS vfs_streams_xattr_init(void);
1040 NTSTATUS vfs_streams_xattr_init(void)
1041 {
1042         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_xattr",
1043                                 streams_xattr_ops);
1044 }