s3: Plumb smb_filename through SMB_VFS_STAT and SMB_VFS_LSTAT
[amitay/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 *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 char *oldname,
582                                 const char *newname)
583 {
584         NTSTATUS status;
585         TALLOC_CTX *frame = NULL;
586         char *obase;
587         char *ostream;
588         char *nbase;
589         char *nstream;
590         const char *base;
591         int ret = -1;
592         char *oxattr_name;
593         char *nxattr_name;
594         bool o_is_stream;
595         bool n_is_stream;
596         ssize_t oret;
597         ssize_t nret;
598         struct ea_struct ea;
599
600         o_is_stream = is_ntfs_stream_name(oldname);
601         n_is_stream = is_ntfs_stream_name(newname);
602
603         if (!o_is_stream && !n_is_stream) {
604                 return SMB_VFS_NEXT_RENAME(handle, oldname, newname);
605         }
606
607         frame = talloc_stackframe();
608         if (!frame) {
609                 goto fail;
610         }
611
612         status = split_ntfs_stream_name(talloc_tos(), oldname, &obase, &ostream);
613         if (!NT_STATUS_IS_OK(status)) {
614                 errno = EINVAL;
615                 goto fail;
616         }
617
618         status = split_ntfs_stream_name(talloc_tos(), newname, &nbase, &nstream);
619         if (!NT_STATUS_IS_OK(status)) {
620                 errno = EINVAL;
621                 goto fail;
622         }
623
624         /*TODO: maybe call SMB_VFS_NEXT_RENAME() both streams are NULL (::$DATA) */
625         if (ostream == NULL) {
626                 errno = ENOSYS;
627                 goto fail;
628         }
629
630         if (nstream == NULL) {
631                 errno = ENOSYS;
632                 goto fail;
633         }
634
635         if (StrCaseCmp(ostream, nstream) == 0) {
636                 goto done;
637         }
638
639         base = obase;
640
641         oxattr_name = talloc_asprintf(talloc_tos(), "%s%s",
642                                       SAMBA_XATTR_DOSSTREAM_PREFIX, ostream);
643         if (oxattr_name == NULL) {
644                 errno = ENOMEM;
645                 goto fail;
646         }
647
648         nxattr_name = talloc_asprintf(talloc_tos(), "%s%s",
649                                       SAMBA_XATTR_DOSSTREAM_PREFIX, nstream);
650         if (nxattr_name == NULL) {
651                 errno = ENOMEM;
652                 goto fail;
653         }
654
655         /* read the old stream */
656         status = get_ea_value(talloc_tos(), handle->conn, NULL,
657                               base, oxattr_name, &ea);
658         if (!NT_STATUS_IS_OK(status)) {
659                 errno = ENOENT;
660                 goto fail;
661         }
662
663         /* (over)write the new stream */
664         nret = SMB_VFS_SETXATTR(handle->conn, base, nxattr_name,
665                                 ea.value.data, ea.value.length, 0);
666         if (nret < 0) {
667                 if (errno == ENOATTR) {
668                         errno = ENOENT;
669                 }
670                 goto fail;
671         }
672
673         /* remove the old stream */
674         oret = SMB_VFS_REMOVEXATTR(handle->conn, base, oxattr_name);
675         if (oret < 0) {
676                 if (errno == ENOATTR) {
677                         errno = ENOENT;
678                 }
679                 goto fail;
680         }
681
682  done:
683         errno = 0;
684         ret = 0;
685  fail:
686         TALLOC_FREE(frame);
687         return ret;
688 }
689
690 static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
691                                    const char *fname,
692                                    bool (*fn)(struct ea_struct *ea,
693                                               void *private_data),
694                                    void *private_data)
695 {
696         NTSTATUS status;
697         char **names;
698         size_t i, num_names;
699         size_t prefix_len = strlen(SAMBA_XATTR_DOSSTREAM_PREFIX);
700
701         status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
702                                         &names, &num_names);
703         if (!NT_STATUS_IS_OK(status)) {
704                 return status;
705         }
706
707         for (i=0; i<num_names; i++) {
708                 struct ea_struct ea;
709
710                 if (strncmp(names[i], SAMBA_XATTR_DOSSTREAM_PREFIX,
711                             prefix_len) != 0) {
712                         continue;
713                 }
714
715                 status = get_ea_value(names, conn, fsp, fname, names[i], &ea);
716                 if (!NT_STATUS_IS_OK(status)) {
717                         DEBUG(10, ("Could not get ea %s for file %s: %s\n",
718                                    names[i], fname, nt_errstr(status)));
719                         continue;
720                 }
721
722                 ea.name = talloc_asprintf(ea.value.data, ":%s",
723                                           names[i] + prefix_len);
724                 if (ea.name == NULL) {
725                         DEBUG(0, ("talloc failed\n"));
726                         continue;
727                 }
728
729                 if (!fn(&ea, private_data)) {
730                         TALLOC_FREE(ea.value.data);
731                         return NT_STATUS_OK;
732                 }
733
734                 TALLOC_FREE(ea.value.data);
735         }
736
737         TALLOC_FREE(names);
738         return NT_STATUS_OK;
739 }
740
741 static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
742                            struct stream_struct **streams,
743                            const char *name, SMB_OFF_T size,
744                            SMB_OFF_T alloc_size)
745 {
746         struct stream_struct *tmp;
747
748         tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct,
749                                    (*num_streams)+1);
750         if (tmp == NULL) {
751                 return false;
752         }
753
754         tmp[*num_streams].name = talloc_strdup(tmp, name);
755         if (tmp[*num_streams].name == NULL) {
756                 return false;
757         }
758
759         tmp[*num_streams].size = size;
760         tmp[*num_streams].alloc_size = alloc_size;
761
762         *streams = tmp;
763         *num_streams += 1;
764         return true;
765 }
766
767 struct streaminfo_state {
768         TALLOC_CTX *mem_ctx;
769         vfs_handle_struct *handle;
770         unsigned int num_streams;
771         struct stream_struct *streams;
772         NTSTATUS status;
773 };
774
775 static bool collect_one_stream(struct ea_struct *ea, void *private_data)
776 {
777         struct streaminfo_state *state =
778                 (struct streaminfo_state *)private_data;
779
780         if (!add_one_stream(state->mem_ctx,
781                             &state->num_streams, &state->streams,
782                             ea->name, ea->value.length-1,
783                             smb_roundup(state->handle->conn,
784                                         ea->value.length-1))) {
785                 state->status = NT_STATUS_NO_MEMORY;
786                 return false;
787         }
788
789         return true;
790 }
791
792 static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle,
793                                          struct files_struct *fsp,
794                                          const char *fname,
795                                          TALLOC_CTX *mem_ctx,
796                                          unsigned int *pnum_streams,
797                                          struct stream_struct **pstreams)
798 {
799         SMB_STRUCT_STAT sbuf;
800         int ret;
801         NTSTATUS status;
802         struct streaminfo_state state;
803
804         if ((fsp != NULL) && (fsp->fh->fd != -1)) {
805                 if (is_ntfs_stream_name(fsp->fsp_name)) {
806                         return NT_STATUS_INVALID_PARAMETER;
807                 }
808                 ret = SMB_VFS_FSTAT(fsp, &sbuf);
809         }
810         else {
811                 if (is_ntfs_stream_name(fname)) {
812                         return NT_STATUS_INVALID_PARAMETER;
813                 }
814                 if (lp_posix_pathnames()) {
815                         ret = vfs_lstat_smb_fname(handle->conn, fname, &sbuf);
816                 } else {
817                         ret = vfs_stat_smb_fname(handle->conn, fname, &sbuf);
818                 }
819         }
820
821         if (ret == -1) {
822                 return map_nt_error_from_unix(errno);
823         }
824
825         state.streams = NULL;
826         state.num_streams = 0;
827
828         if (!S_ISDIR(sbuf.st_ex_mode)) {
829                 if (!add_one_stream(mem_ctx,
830                                     &state.num_streams, &state.streams,
831                                     "::$DATA", sbuf.st_ex_size,
832                                     SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp,
833                                                            &sbuf))) {
834                         return NT_STATUS_NO_MEMORY;
835                 }
836         }
837
838         state.mem_ctx = mem_ctx;
839         state.handle = handle;
840         state.status = NT_STATUS_OK;
841
842         status = walk_xattr_streams(handle->conn, fsp, fname,
843                                     collect_one_stream, &state);
844
845         if (!NT_STATUS_IS_OK(status)) {
846                 TALLOC_FREE(state.streams);
847                 return status;
848         }
849
850         if (!NT_STATUS_IS_OK(state.status)) {
851                 TALLOC_FREE(state.streams);
852                 return state.status;
853         }
854
855         *pnum_streams = state.num_streams;
856         *pstreams = state.streams;
857         return NT_STATUS_OK;
858 }
859
860 static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle)
861 {
862         return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS;
863 }
864
865 static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
866                                     files_struct *fsp, const void *data,
867                                     size_t n, SMB_OFF_T offset)
868 {
869         struct stream_io *sio =
870                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
871         struct ea_struct ea;
872         NTSTATUS status;
873         int ret;
874
875         DEBUG(10, ("streams_xattr_pwrite called for %d bytes\n", (int)n));
876
877         if (sio == NULL) {
878                 return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
879         }
880
881         if (!streams_xattr_recheck(sio)) {
882                 return -1;
883         }
884
885         status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
886                               sio->base, sio->xattr_name, &ea);
887         if (!NT_STATUS_IS_OK(status)) {
888                 return -1;
889         }
890
891         if ((offset + n) > ea.value.length-1) {
892                 uint8 *tmp;
893
894                 tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
895                                            offset + n + 1);
896
897                 if (tmp == NULL) {
898                         TALLOC_FREE(ea.value.data);
899                         errno = ENOMEM;
900                         return -1;
901                 }
902                 ea.value.data = tmp;
903                 ea.value.length = offset + n + 1;
904                 ea.value.data[offset+n] = 0;
905         }
906
907         memcpy(ea.value.data + offset, data, n);
908
909         if (fsp->base_fsp->fh->fd != -1) {
910                 ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
911                                 sio->xattr_name,
912                                 ea.value.data, ea.value.length, 0);
913         } else {
914                 ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name,
915                                 sio->xattr_name,
916                                 ea.value.data, ea.value.length, 0);
917         }
918         TALLOC_FREE(ea.value.data);
919
920         if (ret == -1) {
921                 return -1;
922         }
923
924         return n;
925 }
926
927 static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
928                                    files_struct *fsp, void *data,
929                                    size_t n, SMB_OFF_T offset)
930 {
931         struct stream_io *sio =
932                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
933         struct ea_struct ea;
934         NTSTATUS status;
935         size_t length, overlap;
936
937         if (sio == NULL) {
938                 return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
939         }
940
941         if (!streams_xattr_recheck(sio)) {
942                 return -1;
943         }
944
945         status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
946                               sio->base, sio->xattr_name, &ea);
947         if (!NT_STATUS_IS_OK(status)) {
948                 return -1;
949         }
950
951         length = ea.value.length-1;
952
953         /* Attempt to read past EOF. */
954         if (length <= offset) {
955                 errno = EINVAL;
956                 return -1;
957         }
958
959         overlap = (offset + n) > length ? (length - offset) : n;
960         memcpy(data, ea.value.data + offset, overlap);
961
962         TALLOC_FREE(ea.value.data);
963         return overlap;
964 }
965
966 static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
967                                         struct files_struct *fsp,
968                                         SMB_OFF_T offset)
969 {
970         int ret;
971         uint8 *tmp;
972         struct ea_struct ea;
973         NTSTATUS status;
974         struct stream_io *sio =
975                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
976
977         DEBUG(10, ("streams_xattr_ftruncate called for file %s offset %.0f\n",
978                 fsp->fsp_name,
979                 (double)offset ));
980
981         if (sio == NULL) {
982                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
983         }
984
985         if (!streams_xattr_recheck(sio)) {
986                 return -1;
987         }
988
989         status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
990                               sio->base, sio->xattr_name, &ea);
991         if (!NT_STATUS_IS_OK(status)) {
992                 return -1;
993         }
994
995         tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
996                                    offset + 1);
997
998         if (tmp == NULL) {
999                 TALLOC_FREE(ea.value.data);
1000                 errno = ENOMEM;
1001                 return -1;
1002         }
1003
1004         /* Did we expand ? */
1005         if (ea.value.length < offset + 1) {
1006                 memset(&tmp[ea.value.length], '\0',
1007                         offset + 1 - ea.value.length);
1008         }
1009
1010         ea.value.data = tmp;
1011         ea.value.length = offset + 1;
1012         ea.value.data[offset] = 0;
1013
1014         if (fsp->base_fsp->fh->fd != -1) {
1015                 ret = SMB_VFS_FSETXATTR(fsp->base_fsp,
1016                                 sio->xattr_name,
1017                                 ea.value.data, ea.value.length, 0);
1018         } else {
1019                 ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name,
1020                                 sio->xattr_name,
1021                                 ea.value.data, ea.value.length, 0);
1022         }
1023
1024         TALLOC_FREE(ea.value.data);
1025
1026         if (ret == -1) {
1027                 return -1;
1028         }
1029
1030         return 0;
1031 }
1032
1033 /* VFS operations structure */
1034
1035 static vfs_op_tuple streams_xattr_ops[] = {
1036         {SMB_VFS_OP(streams_xattr_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
1037          SMB_VFS_LAYER_TRANSPARENT},
1038         {SMB_VFS_OP(streams_xattr_open), SMB_VFS_OP_OPEN,
1039          SMB_VFS_LAYER_TRANSPARENT},
1040         {SMB_VFS_OP(streams_xattr_stat), SMB_VFS_OP_STAT,
1041          SMB_VFS_LAYER_TRANSPARENT},
1042         {SMB_VFS_OP(streams_xattr_fstat), SMB_VFS_OP_FSTAT,
1043          SMB_VFS_LAYER_TRANSPARENT},
1044         {SMB_VFS_OP(streams_xattr_lstat), SMB_VFS_OP_LSTAT,
1045          SMB_VFS_LAYER_TRANSPARENT},
1046         {SMB_VFS_OP(streams_xattr_pread), SMB_VFS_OP_PREAD,
1047          SMB_VFS_LAYER_TRANSPARENT},
1048         {SMB_VFS_OP(streams_xattr_pwrite), SMB_VFS_OP_PWRITE,
1049          SMB_VFS_LAYER_TRANSPARENT},
1050         {SMB_VFS_OP(streams_xattr_unlink), SMB_VFS_OP_UNLINK,
1051          SMB_VFS_LAYER_TRANSPARENT},
1052         {SMB_VFS_OP(streams_xattr_rename), SMB_VFS_OP_RENAME,
1053          SMB_VFS_LAYER_TRANSPARENT},
1054         {SMB_VFS_OP(streams_xattr_ftruncate),  SMB_VFS_OP_FTRUNCATE,
1055          SMB_VFS_LAYER_TRANSPARENT},
1056         {SMB_VFS_OP(streams_xattr_streaminfo), SMB_VFS_OP_STREAMINFO,
1057          SMB_VFS_LAYER_OPAQUE},
1058         {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
1059 };
1060
1061 NTSTATUS vfs_streams_xattr_init(void);
1062 NTSTATUS vfs_streams_xattr_init(void)
1063 {
1064         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_xattr",
1065                                 streams_xattr_ops);
1066 }