s3: VFS: Change SMB_VFS_SETXATTR to use const struct smb_filename * instead of const...
[samba.git] / source3 / modules / vfs_streams_xattr.c
1 /*
2  * Store streams in xattrs
3  *
4  * Copyright (C) Volker Lendecke, 2008
5  *
6  * Partly based on James Peach's Darwin module, which is
7  *
8  * Copyright (C) James Peach 2006-2007
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include "includes.h"
25 #include "smbd/smbd.h"
26 #include "system/filesys.h"
27 #include "../lib/crypto/md5.h"
28 #include "lib/util/tevent_unix.h"
29
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_VFS
32
33 struct streams_xattr_config {
34         const char *prefix;
35         size_t prefix_len;
36         bool store_stream_type;
37 };
38
39 struct stream_io {
40         char *base;
41         char *xattr_name;
42         void *fsp_name_ptr;
43         files_struct *fsp;
44         vfs_handle_struct *handle;
45 };
46
47 static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
48 {
49         MD5_CTX ctx;
50         unsigned char hash[16];
51         SMB_INO_T result;
52         char *upper_sname;
53
54         DEBUG(10, ("stream_inode called for %lu/%lu [%s]\n",
55                    (unsigned long)sbuf->st_ex_dev,
56                    (unsigned long)sbuf->st_ex_ino, sname));
57
58         upper_sname = talloc_strdup_upper(talloc_tos(), sname);
59         SMB_ASSERT(upper_sname != NULL);
60
61         MD5Init(&ctx);
62         MD5Update(&ctx, (const unsigned char *)&(sbuf->st_ex_dev),
63                   sizeof(sbuf->st_ex_dev));
64         MD5Update(&ctx, (const unsigned char *)&(sbuf->st_ex_ino),
65                   sizeof(sbuf->st_ex_ino));
66         MD5Update(&ctx, (unsigned char *)upper_sname,
67                   talloc_get_size(upper_sname)-1);
68         MD5Final(hash, &ctx);
69
70         TALLOC_FREE(upper_sname);
71
72         /* Hopefully all the variation is in the lower 4 (or 8) bytes! */
73         memcpy(&result, hash, sizeof(result));
74
75         DEBUG(10, ("stream_inode returns %lu\n", (unsigned long)result));
76
77         return result;
78 }
79
80 static ssize_t get_xattr_size(connection_struct *conn,
81                                 files_struct *fsp,
82                                 const char *fname,
83                                 const char *xattr_name)
84 {
85         NTSTATUS status;
86         struct ea_struct ea;
87         ssize_t result;
88
89         status = get_ea_value(talloc_tos(), conn, fsp, fname,
90                               xattr_name, &ea);
91
92         if (!NT_STATUS_IS_OK(status)) {
93                 return -1;
94         }
95
96         result = ea.value.length-1;
97         TALLOC_FREE(ea.value.data);
98         return result;
99 }
100
101 /**
102  * Given a stream name, populate xattr_name with the xattr name to use for
103  * accessing the stream.
104  */
105 static NTSTATUS streams_xattr_get_name(vfs_handle_struct *handle,
106                                        TALLOC_CTX *ctx,
107                                        const char *stream_name,
108                                        char **xattr_name)
109 {
110         char *sname;
111         char *stype;
112         struct streams_xattr_config *config;
113
114         SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
115                                 return NT_STATUS_UNSUCCESSFUL);
116
117         sname = talloc_strdup(ctx, stream_name + 1);
118         if (sname == NULL) {
119                 return NT_STATUS_NO_MEMORY;
120         }
121
122         /*
123          * With vfs_fruit option "fruit:encoding = native" we're
124          * already converting stream names that contain illegal NTFS
125          * characters from their on-the-wire Unicode Private Range
126          * encoding to their native ASCII representation.
127          *
128          * As as result the name of xattrs storing the streams (via
129          * vfs_streams_xattr) may contain a colon, so we have to use
130          * strrchr_m() instead of strchr_m() for matching the stream
131          * type suffix.
132          *
133          * In check_path_syntax() we've already ensured the streamname
134          * we got from the client is valid.
135          */
136         stype = strrchr_m(sname, ':');
137
138         if (stype) {
139                 /*
140                  * We only support one stream type: "$DATA"
141                  */
142                 if (strcasecmp_m(stype, ":$DATA") != 0) {
143                         talloc_free(sname);
144                         return NT_STATUS_INVALID_PARAMETER;
145                 }
146
147                 /* Split name and type */
148                 stype[0] = '\0';
149         }
150
151         *xattr_name = talloc_asprintf(ctx, "%s%s%s",
152                                       config->prefix,
153                                       sname,
154                                       config->store_stream_type ? ":$DATA" : "");
155         if (*xattr_name == NULL) {
156                 talloc_free(sname);
157                 return NT_STATUS_NO_MEMORY;
158         }
159
160         DEBUG(10, ("xattr_name: %s, stream_name: %s\n", *xattr_name,
161                    stream_name));
162
163         talloc_free(sname);
164         return NT_STATUS_OK;
165 }
166
167 static bool streams_xattr_recheck(struct stream_io *sio)
168 {
169         NTSTATUS status;
170         char *xattr_name = NULL;
171
172         if (sio->fsp->fsp_name == sio->fsp_name_ptr) {
173                 return true;
174         }
175
176         if (sio->fsp->fsp_name->stream_name == NULL) {
177                 /* how can this happen */
178                 errno = EINVAL;
179                 return false;
180         }
181
182         status = streams_xattr_get_name(sio->handle, talloc_tos(),
183                                         sio->fsp->fsp_name->stream_name,
184                                         &xattr_name);
185         if (!NT_STATUS_IS_OK(status)) {
186                 return false;
187         }
188
189         TALLOC_FREE(sio->xattr_name);
190         TALLOC_FREE(sio->base);
191         sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio->handle, sio->fsp),
192                                         xattr_name);
193         sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(sio->handle, sio->fsp),
194                                   sio->fsp->fsp_name->base_name);
195         sio->fsp_name_ptr = sio->fsp->fsp_name;
196
197         TALLOC_FREE(xattr_name);
198
199         if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
200                 return false;
201         }
202
203         return true;
204 }
205
206 /**
207  * Helper to stat/lstat the base file of an smb_fname.
208  */
209 static int streams_xattr_stat_base(vfs_handle_struct *handle,
210                                    struct smb_filename *smb_fname,
211                                    bool follow_links)
212 {
213         char *tmp_stream_name;
214         int result;
215
216         tmp_stream_name = smb_fname->stream_name;
217         smb_fname->stream_name = NULL;
218         if (follow_links) {
219                 result = SMB_VFS_NEXT_STAT(handle, smb_fname);
220         } else {
221                 result = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
222         }
223         smb_fname->stream_name = tmp_stream_name;
224         return result;
225 }
226
227 static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
228                                SMB_STRUCT_STAT *sbuf)
229 {
230         struct smb_filename *smb_fname_base = NULL;
231         int ret = -1;
232         struct stream_io *io = (struct stream_io *)
233                 VFS_FETCH_FSP_EXTENSION(handle, fsp);
234
235         DEBUG(10, ("streams_xattr_fstat called for %d\n", fsp->fh->fd));
236
237         if (io == NULL || fsp->base_fsp == NULL) {
238                 return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
239         }
240
241         if (!streams_xattr_recheck(io)) {
242                 return -1;
243         }
244
245         /* Create an smb_filename with stream_name == NULL. */
246         smb_fname_base = synthetic_smb_fname(talloc_tos(),
247                                         io->base,
248                                         NULL,
249                                         NULL,
250                                         fsp->fsp_name->flags);
251         if (smb_fname_base == NULL) {
252                 errno = ENOMEM;
253                 return -1;
254         }
255
256         if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
257                 ret = SMB_VFS_LSTAT(handle->conn, smb_fname_base);
258         } else {
259                 ret = SMB_VFS_STAT(handle->conn, smb_fname_base);
260         }
261         *sbuf = smb_fname_base->st;
262         TALLOC_FREE(smb_fname_base);
263
264         if (ret == -1) {
265                 return -1;
266         }
267
268         sbuf->st_ex_size = get_xattr_size(handle->conn, fsp,
269                                         io->base, io->xattr_name);
270         if (sbuf->st_ex_size == -1) {
271                 return -1;
272         }
273
274         DEBUG(10, ("sbuf->st_ex_size = %d\n", (int)sbuf->st_ex_size));
275
276         sbuf->st_ex_ino = stream_inode(sbuf, io->xattr_name);
277         sbuf->st_ex_mode &= ~S_IFMT;
278         sbuf->st_ex_mode |= S_IFREG;
279         sbuf->st_ex_blocks = sbuf->st_ex_size / STAT_ST_BLOCKSIZE + 1;
280
281         return 0;
282 }
283
284 static int streams_xattr_stat(vfs_handle_struct *handle,
285                               struct smb_filename *smb_fname)
286 {
287         NTSTATUS status;
288         int result = -1;
289         char *xattr_name = NULL;
290
291         if (!is_ntfs_stream_smb_fname(smb_fname)) {
292                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
293         }
294
295         /* Note if lp_posix_paths() is true, we can never
296          * get here as is_ntfs_stream_smb_fname() is
297          * always false. So we never need worry about
298          * not following links here. */
299
300         /* If the default stream is requested, just stat the base file. */
301         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
302                 return streams_xattr_stat_base(handle, smb_fname, true);
303         }
304
305         /* Populate the stat struct with info from the base file. */
306         if (streams_xattr_stat_base(handle, smb_fname, true) == -1) {
307                 return -1;
308         }
309
310         /* Derive the xattr name to lookup. */
311         status = streams_xattr_get_name(handle, talloc_tos(),
312                                         smb_fname->stream_name, &xattr_name);
313         if (!NT_STATUS_IS_OK(status)) {
314                 errno = map_errno_from_nt_status(status);
315                 return -1;
316         }
317
318         /* Augment the base file's stat information before returning. */
319         smb_fname->st.st_ex_size = get_xattr_size(handle->conn, NULL,
320                                                   smb_fname->base_name,
321                                                   xattr_name);
322         if (smb_fname->st.st_ex_size == -1) {
323                 errno = ENOENT;
324                 result = -1;
325                 goto fail;
326         }
327
328         smb_fname->st.st_ex_ino = stream_inode(&smb_fname->st, xattr_name);
329         smb_fname->st.st_ex_mode &= ~S_IFMT;
330         smb_fname->st.st_ex_mode |= S_IFREG;
331         smb_fname->st.st_ex_blocks =
332             smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;
333
334         result = 0;
335  fail:
336         TALLOC_FREE(xattr_name);
337         return result;
338 }
339
340 static int streams_xattr_lstat(vfs_handle_struct *handle,
341                                struct smb_filename *smb_fname)
342 {
343         NTSTATUS status;
344         int result = -1;
345         char *xattr_name = NULL;
346
347         if (!is_ntfs_stream_smb_fname(smb_fname)) {
348                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
349         }
350
351         /* If the default stream is requested, just stat the base file. */
352         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
353                 return streams_xattr_stat_base(handle, smb_fname, false);
354         }
355
356         /* Populate the stat struct with info from the base file. */
357         if (streams_xattr_stat_base(handle, smb_fname, false) == -1) {
358                 return -1;
359         }
360
361         /* Derive the xattr name to lookup. */
362         status = streams_xattr_get_name(handle, talloc_tos(),
363                                         smb_fname->stream_name, &xattr_name);
364         if (!NT_STATUS_IS_OK(status)) {
365                 errno = map_errno_from_nt_status(status);
366                 return -1;
367         }
368
369         /* Augment the base file's stat information before returning. */
370         smb_fname->st.st_ex_size = get_xattr_size(handle->conn, NULL,
371                                                   smb_fname->base_name,
372                                                   xattr_name);
373         if (smb_fname->st.st_ex_size == -1) {
374                 errno = ENOENT;
375                 result = -1;
376                 goto fail;
377         }
378
379         smb_fname->st.st_ex_ino = stream_inode(&smb_fname->st, xattr_name);
380         smb_fname->st.st_ex_mode &= ~S_IFMT;
381         smb_fname->st.st_ex_mode |= S_IFREG;
382         smb_fname->st.st_ex_blocks =
383             smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;
384
385         result = 0;
386
387  fail:
388         TALLOC_FREE(xattr_name);
389         return result;
390 }
391
392 static int streams_xattr_open(vfs_handle_struct *handle,
393                               struct smb_filename *smb_fname,
394                               files_struct *fsp, int flags, mode_t mode)
395 {
396         NTSTATUS status;
397         struct smb_filename *smb_fname_base = NULL;
398         struct stream_io *sio;
399         struct ea_struct ea;
400         char *xattr_name = NULL;
401         int baseflags;
402         int hostfd = -1;
403         int ret;
404
405         DEBUG(10, ("streams_xattr_open called for %s with flags 0x%x\n",
406                    smb_fname_str_dbg(smb_fname), flags));
407
408         if (!is_ntfs_stream_smb_fname(smb_fname)) {
409                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
410         }
411
412         /* If the default stream is requested, just open the base file. */
413         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
414                 char *tmp_stream_name;
415
416                 tmp_stream_name = smb_fname->stream_name;
417                 smb_fname->stream_name = NULL;
418
419                 ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
420
421                 smb_fname->stream_name = tmp_stream_name;
422
423                 return ret;
424         }
425
426         status = streams_xattr_get_name(handle, talloc_tos(),
427                                         smb_fname->stream_name, &xattr_name);
428         if (!NT_STATUS_IS_OK(status)) {
429                 errno = map_errno_from_nt_status(status);
430                 goto fail;
431         }
432
433         /* Create an smb_filename with stream_name == NULL. */
434         smb_fname_base = synthetic_smb_fname(talloc_tos(),
435                                 smb_fname->base_name,
436                                 NULL,
437                                 NULL,
438                                 smb_fname->flags);
439         if (smb_fname_base == NULL) {
440                 errno = ENOMEM;
441                 goto fail;
442         }
443
444         /*
445          * We use baseflags to turn off nasty side-effects when opening the
446          * underlying file.
447          */
448         baseflags = flags;
449         baseflags &= ~O_TRUNC;
450         baseflags &= ~O_EXCL;
451         baseflags &= ~O_CREAT;
452
453         hostfd = SMB_VFS_NEXT_OPEN(handle, smb_fname_base, fsp,
454                                    baseflags, mode);
455
456         /* It is legit to open a stream on a directory, but the base
457          * fd has to be read-only.
458          */
459         if ((hostfd == -1) && (errno == EISDIR)) {
460                 baseflags &= ~O_ACCMODE;
461                 baseflags |= O_RDONLY;
462                 hostfd = SMB_VFS_NEXT_OPEN(handle, smb_fname_base, fsp, baseflags,
463                                            mode);
464         }
465
466         TALLOC_FREE(smb_fname_base);
467
468         if (hostfd == -1) {
469                 goto fail;
470         }
471
472         status = get_ea_value(talloc_tos(), handle->conn, NULL,
473                               smb_fname->base_name, xattr_name, &ea);
474
475         DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status)));
476
477         if (!NT_STATUS_IS_OK(status)
478             && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
479                 /*
480                  * The base file is not there. This is an error even if we got
481                  * O_CREAT, the higher levels should have created the base
482                  * file for us.
483                  */
484                 DEBUG(10, ("streams_xattr_open: base file %s not around, "
485                            "returning ENOENT\n", smb_fname->base_name));
486                 errno = ENOENT;
487                 goto fail;
488         }
489
490         if ((!NT_STATUS_IS_OK(status) && (flags & O_CREAT)) ||
491             (flags & O_TRUNC)) {
492                 /*
493                  * The attribute does not exist or needs to be truncated
494                  */
495
496                 /*
497                  * Darn, xattrs need at least 1 byte
498                  */
499                 char null = '\0';
500
501                 DEBUG(10, ("creating or truncating attribute %s on file %s\n",
502                            xattr_name, smb_fname->base_name));
503
504                 fsp->fh->fd = hostfd;
505                 ret = SMB_VFS_FSETXATTR(fsp, xattr_name,
506                                         &null, sizeof(null),
507                                         flags & O_EXCL ? XATTR_CREATE : 0);
508                 fsp->fh->fd = -1;
509                 if (ret != 0) {
510                         goto fail;
511                 }
512         }
513
514         sio = (struct stream_io *)VFS_ADD_FSP_EXTENSION(handle, fsp,
515                                                         struct stream_io,
516                                                         NULL);
517         if (sio == NULL) {
518                 errno = ENOMEM;
519                 goto fail;
520         }
521
522         sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
523                                         xattr_name);
524         /*
525          * so->base needs to be a copy of fsp->fsp_name->base_name,
526          * making it identical to streams_xattr_recheck(). If the
527          * open is changing directories, fsp->fsp_name->base_name
528          * will be the full path from the share root, whilst
529          * smb_fname will be relative to the $cwd.
530          */
531         sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
532                                   fsp->fsp_name->base_name);
533         sio->fsp_name_ptr = fsp->fsp_name;
534         sio->handle = handle;
535         sio->fsp = fsp;
536
537         if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
538                 errno = ENOMEM;
539                 goto fail;
540         }
541
542         return hostfd;
543
544  fail:
545         if (hostfd >= 0) {
546                 /*
547                  * BUGBUGBUG -- we would need to call fd_close_posix here, but
548                  * we don't have a full fsp yet
549                  */
550                 fsp->fh->fd = hostfd;
551                 SMB_VFS_NEXT_CLOSE(handle, fsp);
552         }
553
554         return -1;
555 }
556
557 static int streams_xattr_unlink(vfs_handle_struct *handle,
558                                 const struct smb_filename *smb_fname)
559 {
560         NTSTATUS status;
561         int ret = -1;
562         char *xattr_name = NULL;
563
564         if (!is_ntfs_stream_smb_fname(smb_fname)) {
565                 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
566         }
567
568         /* If the default stream is requested, just open the base file. */
569         if (is_ntfs_default_stream_smb_fname(smb_fname)) {
570                 struct smb_filename *smb_fname_base = NULL;
571
572                 smb_fname_base = cp_smb_filename(talloc_tos(), smb_fname);
573                 if (smb_fname_base == NULL) {
574                         errno = ENOMEM;
575                         return -1;
576                 }
577
578                 ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_base);
579
580                 TALLOC_FREE(smb_fname_base);
581                 return ret;
582         }
583
584         status = streams_xattr_get_name(handle, talloc_tos(),
585                                         smb_fname->stream_name, &xattr_name);
586         if (!NT_STATUS_IS_OK(status)) {
587                 errno = map_errno_from_nt_status(status);
588                 goto fail;
589         }
590
591         ret = SMB_VFS_REMOVEXATTR(handle->conn, smb_fname, xattr_name);
592
593         if ((ret == -1) && (errno == ENOATTR)) {
594                 errno = ENOENT;
595                 goto fail;
596         }
597
598         ret = 0;
599
600  fail:
601         TALLOC_FREE(xattr_name);
602         return ret;
603 }
604
605 static int streams_xattr_rename(vfs_handle_struct *handle,
606                                 const struct smb_filename *smb_fname_src,
607                                 const struct smb_filename *smb_fname_dst)
608 {
609         NTSTATUS status;
610         int ret = -1;
611         char *src_xattr_name = NULL;
612         char *dst_xattr_name = NULL;
613         bool src_is_stream, dst_is_stream;
614         ssize_t oret;
615         ssize_t nret;
616         struct ea_struct ea;
617
618         src_is_stream = is_ntfs_stream_smb_fname(smb_fname_src);
619         dst_is_stream = is_ntfs_stream_smb_fname(smb_fname_dst);
620
621         if (!src_is_stream && !dst_is_stream) {
622                 return SMB_VFS_NEXT_RENAME(handle, smb_fname_src,
623                                            smb_fname_dst);
624         }
625
626         /* For now don't allow renames from or to the default stream. */
627         if (is_ntfs_default_stream_smb_fname(smb_fname_src) ||
628             is_ntfs_default_stream_smb_fname(smb_fname_dst)) {
629                 errno = ENOSYS;
630                 goto done;
631         }
632
633         /* Don't rename if the streams are identical. */
634         if (strcasecmp_m(smb_fname_src->stream_name,
635                        smb_fname_dst->stream_name) == 0) {
636                 goto done;
637         }
638
639         /* Get the xattr names. */
640         status = streams_xattr_get_name(handle, talloc_tos(),
641                                         smb_fname_src->stream_name,
642                                         &src_xattr_name);
643         if (!NT_STATUS_IS_OK(status)) {
644                 errno = map_errno_from_nt_status(status);
645                 goto fail;
646         }
647         status = streams_xattr_get_name(handle, talloc_tos(),
648                                         smb_fname_dst->stream_name,
649                                         &dst_xattr_name);
650         if (!NT_STATUS_IS_OK(status)) {
651                 errno = map_errno_from_nt_status(status);
652                 goto fail;
653         }
654
655         /* read the old stream */
656         status = get_ea_value(talloc_tos(), handle->conn, NULL,
657                               smb_fname_src->base_name, src_xattr_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, smb_fname_src,
665                                 dst_xattr_name, ea.value.data, ea.value.length,
666                                 0);
667         if (nret < 0) {
668                 if (errno == ENOATTR) {
669                         errno = ENOENT;
670                 }
671                 goto fail;
672         }
673
674         /* remove the old stream */
675         oret = SMB_VFS_REMOVEXATTR(handle->conn, smb_fname_src,
676                                    src_xattr_name);
677         if (oret < 0) {
678                 if (errno == ENOATTR) {
679                         errno = ENOENT;
680                 }
681                 goto fail;
682         }
683
684  done:
685         errno = 0;
686         ret = 0;
687  fail:
688         TALLOC_FREE(src_xattr_name);
689         TALLOC_FREE(dst_xattr_name);
690         return ret;
691 }
692
693 static NTSTATUS walk_xattr_streams(vfs_handle_struct *handle,
694                                 files_struct *fsp,
695                                 const struct smb_filename *smb_fname,
696                                 bool (*fn)(struct ea_struct *ea,
697                                         void *private_data),
698                                 void *private_data)
699 {
700         NTSTATUS status;
701         char **names;
702         size_t i, num_names;
703         struct streams_xattr_config *config;
704
705         SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
706                                 return NT_STATUS_UNSUCCESSFUL);
707
708         status = get_ea_names_from_file(talloc_tos(),
709                                 handle->conn,
710                                 fsp,
711                                 smb_fname,
712                                 &names,
713                                 &num_names);
714         if (!NT_STATUS_IS_OK(status)) {
715                 return status;
716         }
717
718         for (i=0; i<num_names; i++) {
719                 struct ea_struct ea;
720
721                 /*
722                  * We want to check with samba_private_attr_name()
723                  * whether the xattr name is a private one,
724                  * unfortunately it flags xattrs that begin with the
725                  * default streams prefix as private.
726                  *
727                  * By only calling samba_private_attr_name() in case
728                  * the xattr does NOT begin with the default prefix,
729                  * we know that if it returns 'true' it definitely one
730                  * of our internal xattr like "user.DOSATTRIB".
731                  */
732                 if (strncasecmp_m(names[i], SAMBA_XATTR_DOSSTREAM_PREFIX,
733                                   strlen(SAMBA_XATTR_DOSSTREAM_PREFIX)) != 0) {
734                         if (samba_private_attr_name(names[i])) {
735                                 continue;
736                         }
737                 }
738
739                 if (strncmp(names[i], config->prefix,
740                             config->prefix_len) != 0) {
741                         continue;
742                 }
743
744                 status = get_ea_value(names,
745                                         handle->conn,
746                                         fsp,
747                                         smb_fname->base_name,
748                                         names[i],
749                                         &ea);
750                 if (!NT_STATUS_IS_OK(status)) {
751                         DEBUG(10, ("Could not get ea %s for file %s: %s\n",
752                                 names[i],
753                                 smb_fname->base_name,
754                                 nt_errstr(status)));
755                         continue;
756                 }
757
758                 ea.name = talloc_asprintf(
759                         ea.value.data, ":%s%s",
760                         names[i] + config->prefix_len,
761                         config->store_stream_type ? "" : ":$DATA");
762                 if (ea.name == NULL) {
763                         DEBUG(0, ("talloc failed\n"));
764                         continue;
765                 }
766
767                 if (!fn(&ea, private_data)) {
768                         TALLOC_FREE(ea.value.data);
769                         return NT_STATUS_OK;
770                 }
771
772                 TALLOC_FREE(ea.value.data);
773         }
774
775         TALLOC_FREE(names);
776         return NT_STATUS_OK;
777 }
778
779 static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
780                            struct stream_struct **streams,
781                            const char *name, off_t size,
782                            off_t alloc_size)
783 {
784         struct stream_struct *tmp;
785
786         tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
787                                    (*num_streams)+1);
788         if (tmp == NULL) {
789                 return false;
790         }
791
792         tmp[*num_streams].name = talloc_strdup(tmp, name);
793         if (tmp[*num_streams].name == NULL) {
794                 return false;
795         }
796
797         tmp[*num_streams].size = size;
798         tmp[*num_streams].alloc_size = alloc_size;
799
800         *streams = tmp;
801         *num_streams += 1;
802         return true;
803 }
804
805 struct streaminfo_state {
806         TALLOC_CTX *mem_ctx;
807         vfs_handle_struct *handle;
808         unsigned int num_streams;
809         struct stream_struct *streams;
810         NTSTATUS status;
811 };
812
813 static bool collect_one_stream(struct ea_struct *ea, void *private_data)
814 {
815         struct streaminfo_state *state =
816                 (struct streaminfo_state *)private_data;
817
818         if (!add_one_stream(state->mem_ctx,
819                             &state->num_streams, &state->streams,
820                             ea->name, ea->value.length-1,
821                             smb_roundup(state->handle->conn,
822                                         ea->value.length-1))) {
823                 state->status = NT_STATUS_NO_MEMORY;
824                 return false;
825         }
826
827         return true;
828 }
829
830 static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle,
831                                          struct files_struct *fsp,
832                                          const struct smb_filename *smb_fname,
833                                          TALLOC_CTX *mem_ctx,
834                                          unsigned int *pnum_streams,
835                                          struct stream_struct **pstreams)
836 {
837         SMB_STRUCT_STAT sbuf;
838         int ret;
839         NTSTATUS status;
840         struct streaminfo_state state;
841
842         if ((fsp != NULL) && (fsp->fh->fd != -1)) {
843                 ret = SMB_VFS_FSTAT(fsp, &sbuf);
844         } else {
845                 ret = vfs_stat_smb_basename(handle->conn,
846                                 smb_fname,
847                                 &sbuf);
848         }
849
850         if (ret == -1) {
851                 return map_nt_error_from_unix(errno);
852         }
853
854         state.streams = *pstreams;
855         state.num_streams = *pnum_streams;
856         state.mem_ctx = mem_ctx;
857         state.handle = handle;
858         state.status = NT_STATUS_OK;
859
860         if (S_ISLNK(sbuf.st_ex_mode)) {
861                 /*
862                  * Currently we do't have SMB_VFS_LLISTXATTR
863                  * inside the VFS which means there's no way
864                  * to cope with a symlink when lp_posix_pathnames().
865                  * returns true. For now ignore links.
866                  * FIXME - by adding SMB_VFS_LLISTXATTR. JRA.
867                  */
868                 status = NT_STATUS_OK;
869         } else {
870                 status = walk_xattr_streams(handle, fsp, smb_fname,
871                                     collect_one_stream, &state);
872         }
873
874         if (!NT_STATUS_IS_OK(status)) {
875                 TALLOC_FREE(state.streams);
876                 return status;
877         }
878
879         if (!NT_STATUS_IS_OK(state.status)) {
880                 TALLOC_FREE(state.streams);
881                 return state.status;
882         }
883
884         *pnum_streams = state.num_streams;
885         *pstreams = state.streams;
886
887         return SMB_VFS_NEXT_STREAMINFO(handle,
888                         fsp,
889                         smb_fname,
890                         mem_ctx,
891                         pnum_streams,
892                         pstreams);
893 }
894
895 static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle,
896                         enum timestamp_set_resolution *p_ts_res)
897 {
898         return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS;
899 }
900
901 static int streams_xattr_connect(vfs_handle_struct *handle,
902                                  const char *service, const char *user)
903 {
904         struct streams_xattr_config *config;
905         const char *default_prefix = SAMBA_XATTR_DOSSTREAM_PREFIX;
906         const char *prefix;
907         int rc;
908
909         rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
910         if (rc != 0) {
911                 return rc;
912         }
913
914         config = talloc_zero(handle->conn, struct streams_xattr_config);
915         if (config == NULL) {
916                 DEBUG(1, ("talloc_zero() failed\n"));
917                 errno = ENOMEM;
918                 return -1;
919         }
920
921         prefix = lp_parm_const_string(SNUM(handle->conn),
922                                       "streams_xattr", "prefix",
923                                       default_prefix);
924         config->prefix = talloc_strdup(config, prefix);
925         if (config->prefix == NULL) {
926                 DEBUG(1, ("talloc_strdup() failed\n"));
927                 errno = ENOMEM;
928                 return -1;
929         }
930         config->prefix_len = strlen(config->prefix);
931         DEBUG(10, ("streams_xattr using stream prefix: %s\n", config->prefix));
932
933         config->store_stream_type = lp_parm_bool(SNUM(handle->conn),
934                                                  "streams_xattr",
935                                                  "store_stream_type",
936                                                  true);
937
938         SMB_VFS_HANDLE_SET_DATA(handle, config,
939                                 NULL, struct stream_xattr_config,
940                                 return -1);
941
942         return 0;
943 }
944
945 static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
946                                     files_struct *fsp, const void *data,
947                                     size_t n, off_t offset)
948 {
949         struct stream_io *sio =
950                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
951         struct ea_struct ea;
952         NTSTATUS status;
953         int ret;
954
955         DEBUG(10, ("streams_xattr_pwrite called for %d bytes\n", (int)n));
956
957         if (sio == NULL) {
958                 return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
959         }
960
961         if (!streams_xattr_recheck(sio)) {
962                 return -1;
963         }
964
965         status = get_ea_value(talloc_tos(), handle->conn, fsp,
966                               sio->base, sio->xattr_name, &ea);
967         if (!NT_STATUS_IS_OK(status)) {
968                 return -1;
969         }
970
971         if ((offset + n) > ea.value.length-1) {
972                 uint8_t *tmp;
973
974                 tmp = talloc_realloc(talloc_tos(), ea.value.data, uint8_t,
975                                            offset + n + 1);
976
977                 if (tmp == NULL) {
978                         TALLOC_FREE(ea.value.data);
979                         errno = ENOMEM;
980                         return -1;
981                 }
982                 ea.value.data = tmp;
983                 ea.value.length = offset + n + 1;
984                 ea.value.data[offset+n] = 0;
985         }
986
987         memcpy(ea.value.data + offset, data, n);
988
989         if (fsp->fh->fd != -1) {
990                 ret = SMB_VFS_FSETXATTR(fsp,
991                                 sio->xattr_name,
992                                 ea.value.data, ea.value.length, 0);
993         } else {
994                 ret = SMB_VFS_SETXATTR(fsp->conn,
995                                        fsp->fsp_name,
996                                 sio->xattr_name,
997                                 ea.value.data, ea.value.length, 0);
998         }
999         TALLOC_FREE(ea.value.data);
1000
1001         if (ret == -1) {
1002                 return -1;
1003         }
1004
1005         return n;
1006 }
1007
1008 static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
1009                                    files_struct *fsp, void *data,
1010                                    size_t n, off_t offset)
1011 {
1012         struct stream_io *sio =
1013                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
1014         struct ea_struct ea;
1015         NTSTATUS status;
1016         size_t length, overlap;
1017
1018         DEBUG(10, ("streams_xattr_pread: offset=%d, size=%d\n",
1019                    (int)offset, (int)n));
1020
1021         if (sio == NULL) {
1022                 return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
1023         }
1024
1025         if (!streams_xattr_recheck(sio)) {
1026                 return -1;
1027         }
1028
1029         status = get_ea_value(talloc_tos(), handle->conn, fsp,
1030                               sio->base, sio->xattr_name, &ea);
1031         if (!NT_STATUS_IS_OK(status)) {
1032                 return -1;
1033         }
1034
1035         length = ea.value.length-1;
1036
1037         DEBUG(10, ("streams_xattr_pread: get_ea_value returned %d bytes\n",
1038                    (int)length));
1039
1040         /* Attempt to read past EOF. */
1041         if (length <= offset) {
1042                 return 0;
1043         }
1044
1045         overlap = (offset + n) > length ? (length - offset) : n;
1046         memcpy(data, ea.value.data + offset, overlap);
1047
1048         TALLOC_FREE(ea.value.data);
1049         return overlap;
1050 }
1051
1052 struct streams_xattr_pread_state {
1053         ssize_t nread;
1054         struct vfs_aio_state vfs_aio_state;
1055 };
1056
1057 static void streams_xattr_pread_done(struct tevent_req *subreq);
1058
1059 static struct tevent_req *streams_xattr_pread_send(
1060         struct vfs_handle_struct *handle,
1061         TALLOC_CTX *mem_ctx,
1062         struct tevent_context *ev,
1063         struct files_struct *fsp,
1064         void *data,
1065         size_t n, off_t offset)
1066 {
1067         struct tevent_req *req = NULL;
1068         struct tevent_req *subreq = NULL;
1069         struct streams_xattr_pread_state *state = NULL;
1070         struct stream_io *sio =
1071                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
1072
1073         req = tevent_req_create(mem_ctx, &state,
1074                                 struct streams_xattr_pread_state);
1075         if (req == NULL) {
1076                 return NULL;
1077         }
1078
1079         if (sio == NULL) {
1080                 subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp,
1081                                                  data, n, offset);
1082                 if (tevent_req_nomem(req, subreq)) {
1083                         return tevent_req_post(req, ev);
1084                 }
1085                 tevent_req_set_callback(subreq, streams_xattr_pread_done, req);
1086                 return req;
1087         }
1088
1089         state->nread = SMB_VFS_PREAD(fsp, data, n, offset);
1090         if (state->nread != n) {
1091                 if (state->nread != -1) {
1092                         errno = EIO;
1093                 }
1094                 tevent_req_error(req, errno);
1095                 return tevent_req_post(req, ev);
1096         }
1097
1098         tevent_req_done(req);
1099         return tevent_req_post(req, ev);
1100 }
1101
1102 static void streams_xattr_pread_done(struct tevent_req *subreq)
1103 {
1104         struct tevent_req *req = tevent_req_callback_data(
1105                 subreq, struct tevent_req);
1106         struct streams_xattr_pread_state *state = tevent_req_data(
1107                 req, struct streams_xattr_pread_state);
1108
1109         state->nread = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
1110         TALLOC_FREE(subreq);
1111
1112         if (tevent_req_error(req, state->vfs_aio_state.error)) {
1113                 return;
1114         }
1115         tevent_req_done(req);
1116 }
1117
1118 static ssize_t streams_xattr_pread_recv(struct tevent_req *req,
1119                                         struct vfs_aio_state *vfs_aio_state)
1120 {
1121         struct streams_xattr_pread_state *state = tevent_req_data(
1122                 req, struct streams_xattr_pread_state);
1123
1124         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1125                 return -1;
1126         }
1127
1128         *vfs_aio_state = state->vfs_aio_state;
1129         return state->nread;
1130 }
1131
1132 struct streams_xattr_pwrite_state {
1133         ssize_t nwritten;
1134         struct vfs_aio_state vfs_aio_state;
1135 };
1136
1137 static void streams_xattr_pwrite_done(struct tevent_req *subreq);
1138
1139 static struct tevent_req *streams_xattr_pwrite_send(
1140         struct vfs_handle_struct *handle,
1141         TALLOC_CTX *mem_ctx,
1142         struct tevent_context *ev,
1143         struct files_struct *fsp,
1144         const void *data,
1145         size_t n, off_t offset)
1146 {
1147         struct tevent_req *req = NULL;
1148         struct tevent_req *subreq = NULL;
1149         struct streams_xattr_pwrite_state *state = NULL;
1150         struct stream_io *sio =
1151                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
1152
1153         req = tevent_req_create(mem_ctx, &state,
1154                                 struct streams_xattr_pwrite_state);
1155         if (req == NULL) {
1156                 return NULL;
1157         }
1158
1159         if (sio == NULL) {
1160                 subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp,
1161                                                   data, n, offset);
1162                 if (tevent_req_nomem(req, subreq)) {
1163                         return tevent_req_post(req, ev);
1164                 }
1165                 tevent_req_set_callback(subreq, streams_xattr_pwrite_done, req);
1166                 return req;
1167         }
1168
1169         state->nwritten = SMB_VFS_PWRITE(fsp, data, n, offset);
1170         if (state->nwritten != n) {
1171                 if (state->nwritten != -1) {
1172                         errno = EIO;
1173                 }
1174                 tevent_req_error(req, errno);
1175                 return tevent_req_post(req, ev);
1176         }
1177
1178         tevent_req_done(req);
1179         return tevent_req_post(req, ev);
1180 }
1181
1182 static void streams_xattr_pwrite_done(struct tevent_req *subreq)
1183 {
1184         struct tevent_req *req = tevent_req_callback_data(
1185                 subreq, struct tevent_req);
1186         struct streams_xattr_pwrite_state *state = tevent_req_data(
1187                 req, struct streams_xattr_pwrite_state);
1188
1189         state->nwritten = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
1190         TALLOC_FREE(subreq);
1191
1192         if (tevent_req_error(req, state->vfs_aio_state.error)) {
1193                 return;
1194         }
1195         tevent_req_done(req);
1196 }
1197
1198 static ssize_t streams_xattr_pwrite_recv(struct tevent_req *req,
1199                                          struct vfs_aio_state *vfs_aio_state)
1200 {
1201         struct streams_xattr_pwrite_state *state = tevent_req_data(
1202                 req, struct streams_xattr_pwrite_state);
1203
1204         if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
1205                 return -1;
1206         }
1207
1208         *vfs_aio_state = state->vfs_aio_state;
1209         return state->nwritten;
1210 }
1211
1212 static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
1213                                         struct files_struct *fsp,
1214                                         off_t offset)
1215 {
1216         int ret;
1217         uint8_t *tmp;
1218         struct ea_struct ea;
1219         NTSTATUS status;
1220         struct stream_io *sio =
1221                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
1222
1223         DEBUG(10, ("streams_xattr_ftruncate called for file %s offset %.0f\n",
1224                    fsp_str_dbg(fsp), (double)offset));
1225
1226         if (sio == NULL) {
1227                 return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
1228         }
1229
1230         if (!streams_xattr_recheck(sio)) {
1231                 return -1;
1232         }
1233
1234         status = get_ea_value(talloc_tos(), handle->conn, fsp,
1235                               sio->base, sio->xattr_name, &ea);
1236         if (!NT_STATUS_IS_OK(status)) {
1237                 return -1;
1238         }
1239
1240         tmp = talloc_realloc(talloc_tos(), ea.value.data, uint8_t,
1241                                    offset + 1);
1242
1243         if (tmp == NULL) {
1244                 TALLOC_FREE(ea.value.data);
1245                 errno = ENOMEM;
1246                 return -1;
1247         }
1248
1249         /* Did we expand ? */
1250         if (ea.value.length < offset + 1) {
1251                 memset(&tmp[ea.value.length], '\0',
1252                         offset + 1 - ea.value.length);
1253         }
1254
1255         ea.value.data = tmp;
1256         ea.value.length = offset + 1;
1257         ea.value.data[offset] = 0;
1258
1259         if (fsp->fh->fd != -1) {
1260                 ret = SMB_VFS_FSETXATTR(fsp,
1261                                 sio->xattr_name,
1262                                 ea.value.data, ea.value.length, 0);
1263         } else {
1264                 ret = SMB_VFS_SETXATTR(fsp->conn,
1265                                 fsp->fsp_name,
1266                                 sio->xattr_name,
1267                                 ea.value.data, ea.value.length, 0);
1268         }
1269
1270         TALLOC_FREE(ea.value.data);
1271
1272         if (ret == -1) {
1273                 return -1;
1274         }
1275
1276         return 0;
1277 }
1278
1279 static int streams_xattr_fallocate(struct vfs_handle_struct *handle,
1280                                         struct files_struct *fsp,
1281                                         uint32_t mode,
1282                                         off_t offset,
1283                                         off_t len)
1284 {
1285         struct stream_io *sio =
1286                 (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
1287
1288         DEBUG(10, ("streams_xattr_fallocate called for file %s offset %.0f"
1289                 "len = %.0f\n",
1290                 fsp_str_dbg(fsp), (double)offset, (double)len));
1291
1292         if (sio == NULL) {
1293                 return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
1294         }
1295
1296         if (!streams_xattr_recheck(sio)) {
1297                 return -1;
1298         }
1299
1300         /* Let the pwrite code path handle it. */
1301         errno = ENOSYS;
1302         return -1;
1303 }
1304
1305
1306 static struct vfs_fn_pointers vfs_streams_xattr_fns = {
1307         .fs_capabilities_fn = streams_xattr_fs_capabilities,
1308         .connect_fn = streams_xattr_connect,
1309         .open_fn = streams_xattr_open,
1310         .stat_fn = streams_xattr_stat,
1311         .fstat_fn = streams_xattr_fstat,
1312         .lstat_fn = streams_xattr_lstat,
1313         .pread_fn = streams_xattr_pread,
1314         .pwrite_fn = streams_xattr_pwrite,
1315         .pread_send_fn = streams_xattr_pread_send,
1316         .pread_recv_fn = streams_xattr_pread_recv,
1317         .pwrite_send_fn = streams_xattr_pwrite_send,
1318         .pwrite_recv_fn = streams_xattr_pwrite_recv,
1319         .unlink_fn = streams_xattr_unlink,
1320         .rename_fn = streams_xattr_rename,
1321         .ftruncate_fn = streams_xattr_ftruncate,
1322         .fallocate_fn = streams_xattr_fallocate,
1323         .streaminfo_fn = streams_xattr_streaminfo,
1324 };
1325
1326 NTSTATUS vfs_streams_xattr_init(TALLOC_CTX *);
1327 NTSTATUS vfs_streams_xattr_init(TALLOC_CTX *ctx)
1328 {
1329         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_xattr",
1330                                 &vfs_streams_xattr_fns);
1331 }