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