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