]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/xattr.c
68b427a756eefc9892e273c3383f101a22a57ca3
[bacula/bacula] / bacula / src / filed / xattr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2008-2009 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Functions to handle Extended Attributes for bacula.
30  *
31  * Extended Attributes are so OS specific we only restore Extended Attributes if
32  * they were saved using a filed on the same platform.
33  *
34  * Currently we support the following OSes:
35  *   - FreeBSD (Extended Attributes)
36  *   - Darwin (Extended Attributes)
37  *   - Linux (Extended Attributes)
38  *   - NetBSD (Extended Attributes)
39  *   - Solaris (Extended Attributes and Extensible Attributes)
40  *
41  *   Written by Marco van Wieringen, November MMVIII
42  *
43  *   Version $Id$
44  */
45
46 #include "bacula.h"
47 #include "filed.h"
48 #include "xattr.h"
49
50 /*
51  * List of supported OSes. Everything outside that gets stub functions.
52  * Also when XATTR support is explicitly disabled.
53  */
54 #if !defined(HAVE_XATTR)          /* Extended Attributes support is required, of course */ \
55    || !( defined(HAVE_DARWIN_OS)  /* OSX has XATTR support  using getxattr etc. */ \
56       || defined(HAVE_FREEBSD_OS) /* FreeBSD has XATTR support using lgetxattr etc. */ \
57       || defined(HAVE_LINUX_OS)   /* Linux has XATTR support using the lgetxattr etc. */ \
58       || defined(HAVE_NETBSD_OS)  /* NetBSD has XATTR support using the lgetxattr etc. */ \
59       || defined(HAVE_SUN_OS)     /* Solaris has XATTR support using attropen etc. */ \
60         )
61
62 bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
63 {
64    Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
65    return false;
66 }
67
68 bool parse_xattr_stream(JCR *jcr, int stream)
69 {
70    Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
71    return false;
72 }
73
74 #else
75
76 /*
77  * Send a XATTR stream to the SD.
78  */
79 static bool send_xattr_stream(JCR *jcr, int stream)
80 {
81    BSOCK *sd = jcr->store_bsock;
82    POOLMEM *msgsave;
83 #ifdef FD_NO_SEND_TEST
84    return true;
85 #endif
86
87    /*
88     * Sanity check
89     */
90    if (jcr->xattr_data_len <= 0)
91       return true;
92
93    /*
94     * Send header
95     */
96    if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
97       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
98             sd->bstrerror());
99
100       return false;
101    }
102
103    /*
104     * Send the buffer to the storage deamon
105     */
106    Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data);
107    msgsave = sd->msg;
108    sd->msg = jcr->xattr_data;
109    sd->msglen = jcr->xattr_data_len;
110    if (!sd->send()) {
111       sd->msg = msgsave;
112       sd->msglen = 0;
113       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
114             sd->bstrerror());
115
116       return false;
117    }
118
119    jcr->JobBytes += sd->msglen;
120    sd->msg = msgsave;
121    if (!sd->signal(BNET_EOD)) {
122       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
123             sd->bstrerror());
124
125       return false;
126    }
127
128    Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
129
130    return true;
131 }
132
133 /*
134  * This is a supported OS, See what kind of interface we should use.
135  * Start with the generic interface used by most OS-es.
136  */
137 #if defined(HAVE_DARWIN_OS) \
138    || defined(HAVE_FREEBSD_OS) \
139    || defined(HAVE_LINUX_OS) \
140    || defined(HAVE_NETBSD_OS)
141        
142 #ifdef HAVE_SYS_XATTR_H
143 #include <sys/xattr.h>
144 #endif
145
146 /*
147  * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
148  * listxattr, getxattr and setxattr with an extra options argument
149  * which mimics the l variants of the functions when we specify
150  * XATTR_NOFOLLOW as the options value.
151  */
152 #if defined(HAVE_DARWIN_OS)
153    #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
154    #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
155    #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
156 #else
157    /*
158     * Fallback to the non l-functions when those are not available.
159     */
160    #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
161    #define lgetxattr getxattr
162    #endif
163    #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
164    #define lsetxattr setxattr
165    #endif
166    #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
167    #define llistxattr listxattr
168    #endif
169 #endif
170
171 static void xattr_drop_internal_table(xattr_t *xattr_value_list)
172 {
173    xattr_t *current_xattr;
174
175    /*
176     * Walk the list of xattrs and free allocated memory on traversing.
177     */
178    for (current_xattr = xattr_value_list;
179         current_xattr != (xattr_t *)NULL;
180         current_xattr++) {
181       /*
182        * See if we can shortcut.
183        */
184       if (current_xattr->magic != XATTR_MAGIC)
185          break;
186
187       free(current_xattr->name);
188
189       if (current_xattr->value_length > 0)
190          free(current_xattr->value);
191    }
192
193    /*
194     * Free the array of control structs.
195     */
196    free(xattr_value_list);
197 }
198
199 /*
200  * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
201  * which encodes one or more xattr_t structures.
202  *
203  * The Serialized stream consists of the following elements:
204  *    magic - A magic string which makes it easy to detect any binary incompatabilites
205  *    name_length - The length of the following xattr name
206  *    name - The name of the extended attribute
207  *    value_length - The length of the following xattr data
208  *    value - The actual content of the extended attribute
209  *
210  * This is repeated 1 or more times.
211  * 
212  */
213 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list)
214 {
215    xattr_t *current_xattr;
216    ser_declare;
217
218    /*
219     * Make sure the serialized stream fits in the poolmem buffer.
220     * We allocate some more to be sure the stream is gonna fit.
221     */
222    jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, expected_serialize_len + 10);
223    ser_begin(jcr->xattr_data, expected_serialize_len + 10);
224
225    /*
226     * Walk the list of xattrs and serialize the data.
227     */
228    for (current_xattr = xattr_value_list; current_xattr != (xattr_t *)NULL; current_xattr++) {
229       /*
230        * See if we can shortcut.
231        */
232       if (current_xattr->magic != XATTR_MAGIC)
233          break;
234
235       ser_uint32(current_xattr->magic);
236       ser_uint32(current_xattr->name_length);
237       ser_bytes(current_xattr->name, current_xattr->name_length);
238
239       ser_uint32(current_xattr->value_length);
240       ser_bytes(current_xattr->value, current_xattr->value_length);
241    }
242
243    ser_end(jcr->xattr_data, expected_serialize_len + 10);
244    jcr->xattr_data_len = ser_length(jcr->xattr_data);
245
246    return jcr->xattr_data_len;
247 }
248
249 static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
250 {
251    int count = 0;
252    int32_t xattr_list_len,
253            xattr_value_len;
254    uint32_t expected_serialize_len = 0;
255    char *xattr_list, *bp;
256    xattr_t *xattr_value_list, *current_xattr;
257
258    /*
259     * First get the length of the available list with extended attributes.
260     */
261    xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
262    if (xattr_list_len < 0) {
263       berrno be;
264       Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
265          jcr->last_fname, be.bstrerror());
266       Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
267          jcr->last_fname, be.bstrerror());
268
269       return false;
270    } else if (xattr_list_len == 0) {
271       return true;
272    }
273
274    /*
275     * Allocate room for the extented attribute list.
276     */
277    if ((xattr_list = (char *)malloc(xattr_list_len + 1)) == (char *)NULL) {
278       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), xattr_list_len + 1);
279
280       return false;
281    }
282    memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
283
284    /*
285     * Get the actual list of extended attributes names for a file.
286     */
287    xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
288    if (xattr_list_len < 0) {
289       berrno be;
290       Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
291          jcr->last_fname, be.bstrerror());
292       Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
293          jcr->last_fname, be.bstrerror());
294
295       free(xattr_list);
296
297       return false;
298    }
299    xattr_list[xattr_list_len] = '\0';
300
301    /*
302     * Count the number of extended attributes on a file.
303     */
304    bp = xattr_list;
305    while ((bp - xattr_list) + 1 < xattr_list_len) {
306 #if defined(HAVE_LINUX_OS)
307       /*
308        * On Linux you also get the acls in the extented attribute list.
309        * So we check if we are already backing up acls and if we do we
310        * don't store the extended attribute with the same info.
311        */
312       if ((ff_pkt->flags & FO_ACL) == 0 || strcmp(bp, "system.posix_acl_access"))
313          count++;
314 #else
315       count++;
316 #endif
317
318       bp = strchr(bp, '\0') + 1;
319    }
320
321    if (count == 0) {
322       free(xattr_list);
323
324       return true;
325    }
326
327    /*
328     * Allocate enough room to hold all extended attributes.
329     * After allocating the storage make sure its empty by zeroing it.
330     */
331    if ((xattr_value_list = (xattr_t *)malloc(count * sizeof(xattr_t))) == (xattr_t *)NULL) {
332       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), count * sizeof(xattr_t));
333
334       return false;
335    }
336    memset((caddr_t)xattr_value_list, 0, count * sizeof(xattr_t));
337
338    /*
339     * Walk the list of extended attributes names and retrieve the data.
340     * We already count the bytes needed for serializing the stream later on.
341     */
342    current_xattr = xattr_value_list;
343    bp = xattr_list;
344    while ((bp - xattr_list) + 1 < xattr_list_len) {
345 #if defined(HAVE_LINUX_OS)
346       if (ff_pkt->flags & FO_ACL && !strcmp(bp, "system.posix_acl_access")) {
347          bp = strchr(bp, '\0') + 1;
348
349          continue;
350       }
351 #endif
352
353       /*
354        * Each xattr valuepair starts with a magic so we can parse it easier.
355        */
356       current_xattr->magic = XATTR_MAGIC;
357       expected_serialize_len += sizeof(current_xattr->magic);
358
359       /*
360        * Allocate space for storing the name.
361        */
362       current_xattr->name_length = strlen(bp);
363       if ((current_xattr->name = (char *)malloc(current_xattr->name_length)) == (char *)NULL) {
364          Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), current_xattr->name_length);
365
366          goto bail_out;
367       }
368       memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
369
370       expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
371
372       /*
373        * First see how long the value is for the extended attribute.
374        */
375       xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
376       if (xattr_value_len < 0) {
377          berrno be;
378          Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
379             jcr->last_fname, be.bstrerror());
380          Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
381             jcr->last_fname, be.bstrerror());
382
383          goto bail_out;
384       }
385
386       /*
387        * Allocate space for storing the value.
388        */
389       if ((current_xattr->value = (char *)malloc(xattr_value_len)) == (char *)NULL) {
390          Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), xattr_value_len);
391
392          goto bail_out;
393       }
394       memset((caddr_t)current_xattr->value, 0, xattr_value_len);
395
396       xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
397       if (xattr_value_len < 0) {
398          berrno be;
399          Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
400             jcr->last_fname, be.bstrerror());
401          Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
402             jcr->last_fname, be.bstrerror());
403
404          goto bail_out;
405       }
406
407       /*
408        * Store the actual length of the value.
409        */
410       current_xattr->value_length = xattr_value_len;
411       expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
412
413       /*
414        * Protect ourself against things getting out of hand.
415        */
416       if (expected_serialize_len >= MAX_XATTR_STREAM) {
417          Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
418             jcr->last_fname, MAX_XATTR_STREAM);
419
420          goto bail_out;
421       }
422       
423       /*
424        * Next attribute.
425        */
426       current_xattr++;
427       bp = strchr(bp, '\0') + 1;
428    }
429
430    /*
431     * Serialize the datastream.
432     */
433    if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
434       Jmsg1(jcr, M_ERROR, 0, _("Failed to serialize extended attributes on file \"%s\"\n"),
435          jcr->last_fname);
436       Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
437          jcr->last_fname);
438
439       goto bail_out;
440    }
441
442    xattr_drop_internal_table(xattr_value_list);
443    free(xattr_list);
444
445    /*
446     * Send the datastream to the SD.
447     */
448    return send_xattr_stream(jcr, stream);
449
450 bail_out:
451    xattr_drop_internal_table(xattr_value_list);
452    free(xattr_list);
453
454    return false;
455 }
456
457 static bool generic_xattr_parse_streams(JCR *jcr)
458 {
459    unser_declare;
460    xattr_t current_xattr;
461    bool retval = true;
462
463    /*
464     * Parse the stream and perform the setxattr calls on the file.
465     *
466     * Start unserializing the data. We keep on looping while we have not
467     * unserialized all bytes in the stream.
468     */
469    unser_begin(jcr->xattr_data, jcr->xattr_data_len);
470    while (unser_length(jcr->xattr_data) < jcr->xattr_data_len) {
471       /*
472        * First make sure the magic is present. This way we can easily catch corruption.
473        * Any missing MAGIC is fatal we do NOT try to continue.
474        */
475       unser_uint32(current_xattr.magic);
476       if (current_xattr.magic != XATTR_MAGIC) {
477          Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
478             jcr->last_fname);
479          Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
480             jcr->last_fname);
481
482          return false;
483       }
484
485       /*
486        * Decode the valuepair. First decode the length of the name.
487        */
488       unser_uint32(current_xattr.name_length);
489       
490       /*
491        * Allocate room for the name and decode its content.
492        */
493       if ((current_xattr.name = (char *)malloc(current_xattr.name_length + 1)) == (char *)NULL) {
494          Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), current_xattr.name_length + 1);
495
496          return false;
497       }
498       unser_bytes(current_xattr.name, current_xattr.name_length);
499
500       /*
501        * The xattr_name needs to be null terminated for lsetxattr.
502        */
503       current_xattr.name[current_xattr.name_length] = '\0';
504
505       /*
506        * Decode the value length.
507        */
508       unser_uint32(current_xattr.value_length);
509
510       /*
511        * Allocate room for the value and decode its content.
512        */
513       if ((current_xattr.value = (char *)malloc(current_xattr.value_length)) == (char *)NULL) {
514          Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), current_xattr.value_length);
515
516          return false;
517       }
518       unser_bytes(current_xattr.value, current_xattr.value_length);
519
520       /*
521        * Try to set the extended attribute on the file.
522        * If we fail to set this attribute we flag the error but its not fatal,
523        * we try to restore the other extended attributes too.
524        */
525       if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
526          current_xattr.value_length, 0) != 0) {
527          berrno be;
528          Jmsg2(jcr, M_ERROR, 0, _("lsetxattr error on file \"%s\": ERR=%s\n"),
529             jcr->last_fname, be.bstrerror());
530          Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
531             jcr->last_fname, be.bstrerror());
532
533          /*
534           * Reset the return flag to false to indicate one or more extended attributes
535           * could not be restored.
536           */
537          retval = false;
538       }
539
540       /*
541        * Free the temporary buffers.
542        */
543       free(current_xattr.name);
544       free(current_xattr.value);
545    }
546
547    unser_end(jcr->xattr_data, jcr->xattr_data_len);
548    return retval;
549 }
550
551 #if defined(HAVE_DARWIN_OS)
552 static bool darwin_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
553 {
554    return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_DARWIN);
555 }
556
557 static bool darwin_parse_xattr_stream(JCR *jcr, int stream)
558 {
559    switch (stream) {
560    case STREAM_XATTR_DARWIN:
561       return generic_xattr_parse_streams(jcr);
562    default:
563       return false;
564    }
565 }
566 #elif defined(HAVE_FREEBSD_OS)
567 static bool freebsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
568 {
569    return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_FREEBSD);
570 }
571
572 static bool freebsd_parse_xattr_stream(JCR *jcr, int stream)
573 {
574    switch (stream) {
575    case STREAM_XATTR_FREEBSD:
576       return generic_xattr_parse_streams(jcr);
577    default:
578       return false;
579    }
580 }
581 #elif defined(HAVE_LINUX_OS)
582 static bool linux_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
583 {
584    return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_LINUX);
585 }
586
587 static bool linux_parse_xattr_stream(JCR *jcr, int stream)
588 {
589    switch (stream) {
590    case STREAM_XATTR_LINUX:
591       return generic_xattr_parse_streams(jcr);
592    default:
593       return false;
594    }
595 }
596 #elif defined(HAVE_NETBSD_OS)
597 static bool netbsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
598 {
599    return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_NETBSD);
600 }
601
602 static bool netbsd_parse_xattr_stream(JCR *jcr, int stream)
603 {
604    switch (stream) {
605    case STREAM_XATTR_NETBSD:
606       return generic_xattr_parse_streams(jcr);
607    default:
608       return false;
609    }
610 }
611 #endif
612 #elif defined(HAVE_SUN_OS)
613 /*
614  * Solaris extended attributes were introduced in Solaris 9
615  * by PSARC 1999/209
616  *
617  * Solaris extensible attributes were introduced in OpenSolaris
618  * by PSARC 2007/315 Solaris extensible attributes are also
619  * sometimes called extended system attributes.
620  *
621  * man fsattr(5) on Solaris gives a wealth of info. The most
622  * important bits are:
623  *
624  * Attributes are logically supported as files within the  file
625  * system.   The  file  system  is  therefore augmented with an
626  * orthogonal name space of file attributes. Any file  (includ-
627  * ing  attribute files) can have an arbitrarily deep attribute
628  * tree associated with it. Attribute values  are  accessed  by
629  * file descriptors obtained through a special attribute inter-
630  * face.  This logical view of "attributes as files" allows the
631  * leveraging  of  existing file system interface functionality
632  * to support the construction, deletion, and  manipulation  of
633  * attributes.
634  *
635  * The special files  "."  and  ".."  retain  their  accustomed
636  * semantics within the attribute hierarchy.  The "." attribute
637  * file refers to the current directory and the ".."  attribute
638  * file  refers to the parent directory.  The unnamed directory
639  * at the head of each attribute tree is considered the "child"
640  * of  the  file it is associated with and the ".." file refers
641  * to the associated file.  For  any  non-directory  file  with
642  * attributes,  the  ".." entry in the unnamed directory refers
643  * to a file that is not a directory.
644  *
645  * Conceptually, the attribute model is fully general. Extended
646  * attributes  can  be  any  type of file (doors, links, direc-
647  * tories, and so forth) and can even have their own attributes
648  * (fully  recursive).   As a result, the attributes associated
649  * with a file could be an arbitrarily deep directory hierarchy
650  * where each attribute could have an equally complex attribute
651  * tree associated with it.  Not all implementations  are  able
652  * to,  or  want to, support the full model. Implementation are
653  * therefore permitted to reject operations that are  not  sup-
654  * ported.   For  example,  the implementation for the UFS file
655  * system allows only regular files as attributes (for example,
656  * no sub-directories) and rejects attempts to place attributes
657  * on attributes.
658  *
659  * The following list details the operations that are  rejected
660  * in the current implementation:
661  *
662  * link                     Any attempt to create links between
663  *                          attribute  and  non-attribute space
664  *                          is rejected  to  prevent  security-
665  *                          related   or   otherwise  sensitive
666  *                          attributes from being exposed,  and
667  *                          therefore  manipulable,  as regular
668  *                          files.
669  *
670  * rename                   Any  attempt  to   rename   between
671  *                          attribute  and  non-attribute space
672  *                          is rejected to prevent  an  already
673  *                          linked  file from being renamed and
674  *                          thereby circumventing the link res-
675  *                          triction above.
676  *
677  * mkdir, symlink, mknod    Any  attempt  to  create  a   "non-
678  *                          regular" file in attribute space is
679  *                          rejected to reduce the  functional-
680  *                          ity,  and  therefore  exposure  and
681  *                          risk, of  the  initial  implementa-
682  *                          tion.
683  *
684  * The entire available name space has been allocated to  "gen-
685  * eral use" to bring the implementation in line with the NFSv4
686  * draft standard [NFSv4]. That standard defines "named  attri-
687  * butes"  (equivalent  to Solaris Extended Attributes) with no
688  * naming restrictions.  All Sun  applications  making  use  of
689  * opaque extended attributes will use the prefix "SUNW".
690  *
691  */
692 #ifdef HAVE_SYS_ATTR_H
693 #include <sys/attr.h>
694 #endif
695
696 #ifdef HAVE_ATTR_H
697 #include <attr.h>
698 #endif
699
700 #ifdef HAVE_SYS_NVPAIR_H
701 #include <sys/nvpair.h>
702 #endif
703
704 #ifdef HAVE_SYS_ACL_H
705 #include <sys/acl.h>
706 #endif
707
708 /*
709  * This is the count of xattrs saved on a certain file, it gets reset
710  * on each new file processed and is used to see if we need to send
711  * the hidden xattr dir data. We only send that data when we encounter
712  * an other xattr on the file.
713  */
714 static int nr_xattr_saved = 0;
715 static char toplevel_hidden_dir_xattr_data[MAXSTRING];
716 static int toplevel_hidden_dir_xattr_data_len;
717
718 /*
719  * This code creates a temporary cache with entries for each xattr which has
720  * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
721  */
722 static xattr_link_cache_entry_t *xattr_link_cache_head = NULL,
723                                 *xattr_link_cache_tail = NULL;
724
725 static struct xattr_link_cache_entry *find_xattr_link_cache_entry(ino_t inum)
726 {
727    xattr_link_cache_entry_t *ptr;
728
729    for (ptr = xattr_link_cache_head; ptr != NULL; ptr = ptr->next)
730       if (ptr->inum == inum)
731          return ptr;
732
733    return NULL;
734 }
735
736 static void add_xattr_link_cache_entry(ino_t inum, char *target)
737 {
738    xattr_link_cache_entry_t *ptr;
739
740    if ((ptr = (xattr_link_cache_entry_t *)malloc(sizeof(struct xattr_link_cache_entry))) != NULL) {
741       memset((caddr_t)ptr, 0, sizeof(struct xattr_link_cache_entry));
742       ptr->inum = inum;
743       strncpy(ptr->target, target, sizeof(ptr->target));
744       if (xattr_link_cache_head == NULL)
745          xattr_link_cache_head = ptr;
746       if (xattr_link_cache_tail != NULL)
747          xattr_link_cache_tail->next = ptr;
748       xattr_link_cache_tail = ptr;
749    }
750 }
751
752 static void drop_xattr_link_cache(void)
753 {
754    xattr_link_cache_entry_t *ptr, *next;
755
756    for (ptr = xattr_link_cache_tail; ptr != NULL; ptr = next) {
757       next = ptr->next;
758       free(ptr);
759    }
760
761    xattr_link_cache_head = NULL;
762    xattr_link_cache_tail = NULL;
763 }
764
765 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
766 /*
767  * This function returns true if a non default extended system attribute
768  * list is associated with fd and returns false when an error has occured
769  * or when only extended system attributes other than archive,
770  * av_modified or crtime are set.
771  *
772  * The function returns true for the following cases:
773  *
774  * - any extended system attribute other than the default attributes
775  *   ('archive', 'av_modified' and 'crtime') is set
776  * - nvlist has NULL name string
777  * - nvpair has data type of 'nvlist'
778  * - default data type.
779  */
780 static bool solaris_has_non_transient_extensible_attributes(int fd)
781 {
782    boolean_t value;
783    data_type_t type;
784    nvlist_t *response;
785    nvpair_t *pair;
786    f_attr_t fattr;
787    char *name;
788    bool retval = false;
789
790    if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
791       return false;
792    }
793
794    pair = NULL;
795    while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
796       name = nvpair_name(pair);
797
798       if (name != NULL) {
799          fattr = name_to_attr(name);
800       } else {
801          retval = true;
802          goto cleanup;
803       }
804
805       type = nvpair_type(pair);
806       switch (type) {
807       case DATA_TYPE_BOOLEAN_VALUE:
808          if (nvpair_value_boolean_value(pair, &value) != 0) {
809             continue;
810          }
811          if (value && fattr != F_ARCHIVE &&
812                       fattr != F_AV_MODIFIED) {
813             retval = true;
814             goto cleanup;
815          }
816          break;
817       case DATA_TYPE_UINT64_ARRAY:
818          if (fattr != F_CRTIME) {
819             retval = true;
820             goto cleanup;
821          }
822          break;
823       case DATA_TYPE_NVLIST:
824       default:
825          retval = true;
826          goto cleanup;
827       }
828    }
829
830 cleanup:
831    if (response != NULL)
832       nvlist_free(response);
833
834    return retval;
835 }
836 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
837
838 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
839 /*
840  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
841  * There is no need to store those acls as we already store the stat bits too.
842  */
843 static bool acl_is_trivial(int count, aclent_t *entries)
844 {
845    int n;
846    aclent_t *ace;
847
848    for (n = 0; n < count; n++) {
849       ace = &entries[n];
850
851       if (!(ace->a_type == USER_OBJ ||
852             ace->a_type == GROUP_OBJ ||
853             ace->a_type == OTHER_OBJ ||
854             ace->a_type == CLASS_OBJ))
855         return false;
856    }
857
858    return true;
859 }
860 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
861
862 static bool solaris_archive_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
863 {
864 #ifdef HAVE_ACL
865 #ifdef HAVE_EXTENDED_ACL
866    int flags;
867    acl_t *aclp = NULL;
868
869    /*
870     * See if this attribute has an ACL
871     */
872    if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
873        pathconf(attrname, _PC_ACL_ENABLED) > 0) {
874       /*
875        * See if there is a non trivial acl on the file.
876        */
877       if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
878            acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
879          berrno be;
880          Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
881             attrname, jcr->last_fname, be.bstrerror());
882          Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
883             attrname, jcr->last_fname, be.bstrerror());
884
885          return false;
886       }
887
888       if (aclp != NULL) {
889 #if defined(ACL_SID_FMT)
890          /*
891           * New format flag added in newer Solaris versions.
892           */
893          flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
894 #else
895          flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
896 #endif /* ACL_SID_FMT */
897
898          *acl_text = acl_totext(aclp, flags);
899          acl_free(aclp);
900       } else {
901          *acl_text = NULL;
902       }
903    } else {
904       *acl_text = NULL;
905    }
906
907    return true;
908 #else /* HAVE_EXTENDED_ACL */
909    int n;
910    aclent_t *acls = NULL;
911
912    /*
913     * See if this attribute has an ACL
914     */
915    if (fd != -1)
916       n = facl(fd, GETACLCNT, 0, NULL);
917    else
918       n = acl(attrname, GETACLCNT, 0, NULL);
919
920    if (n >= MIN_ACL_ENTRIES) {
921       acls = (aclent_t *)malloc(n * sizeof(aclent_t));
922       if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
923           acl(attrname, GETACL, n, acls) != n) {
924          berrno be;
925          Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
926             attrname, jcr->last_fname, be.bstrerror());
927          Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
928             attrname, jcr->last_fname, be.bstrerror());
929
930          free(acls);
931          return false;
932       }
933
934       /*
935        * See if there is a non trivial acl on the file.
936        */
937       if (!acl_is_trivial(n, acls)) {
938          if ((*acl_text = acltotext(acls, n)) == NULL) {
939             berrno be;
940             Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
941                attrname, jcr->last_fname, be.bstrerror());
942             Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
943                attrname, jcr->last_fname, be.bstrerror());
944
945             free(acls);
946             return false;
947          }
948       } else {
949          *acl_text = NULL;
950       }
951
952      free(acls);
953    } else {
954       *acl_text = NULL;
955    }
956
957    return true;
958 #endif /* HAVE_EXTENDED_ACL */
959 #else /* HAVE_ACL */
960    return NULL;
961 #endif /* HAVE_ACL */
962 }
963
964 /*
965  * Forward declaration for recursive function call.
966  */
967 static bool solaris_archive_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
968
969 /*
970  * Archive an extended or extensible attribute.
971  * This is stored as an opaque stream of bytes with the following encoding:
972  *
973  * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
974  * 
975  * or for a hardlinked or symlinked attribute
976  *
977  * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
978  *
979  * xattr_name can be a subpath relative to the file the xattr is on.
980  * stat_buffer is the string representation of the stat struct.
981  * acl_string is an acl text when a non trivial acl is set on the xattr.
982  * actual_xattr_data is the content of the xattr file.
983  */
984 static bool solaris_archive_xattr(JCR *jcr, int fd, const char *xattr_namespace,
985                                   const char *attrname, bool toplevel_hidden_dir, int stream)
986 {
987    int cnt;
988    int attrfd = -1;
989    struct stat st;
990    struct xattr_link_cache_entry *xlce;
991    char target_attrname[PATH_MAX];
992    char link_source[PATH_MAX];
993    char *acl_text = NULL;
994    char attribs[MAXSTRING];
995    char buffer[BUFSIZ];
996    bool retval = false;
997
998    snprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
999
1000    /*
1001     * Get the stats of the extended or extensible attribute.
1002     */
1003    if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
1004       berrno be;
1005       Jmsg3(jcr, M_ERROR, 0, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
1006          target_attrname, jcr->last_fname, be.bstrerror());
1007       Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
1008          target_attrname, jcr->last_fname, be.bstrerror());
1009
1010       goto cleanup;
1011    }
1012
1013    /*
1014     * Based on the filetype perform the correct action. We support most filetypes here, more
1015     * then the actual implementation on Solaris supports so some code may never get executed
1016     * due to limitations in the implementation.
1017     */
1018    switch (st.st_mode & S_IFMT) {
1019    case S_IFIFO:
1020    case S_IFCHR:
1021    case S_IFBLK:
1022       /*
1023        * Get any acl on the xattr.
1024        */
1025       if (!solaris_archive_xattr_acl(jcr, attrfd, attrname, &acl_text))
1026          goto cleanup;
1027
1028       /*
1029        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1030        * Encode the stat struct into an ASCII representation.
1031        */
1032       encode_stat(attribs, &st, 0, stream);
1033       cnt = snprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
1034                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1035       break;
1036    case S_IFDIR:
1037       /*
1038        * Get any acl on the xattr.
1039        */
1040       if (!solaris_archive_xattr_acl(jcr, attrfd, attrname, &acl_text))
1041          goto cleanup;
1042
1043       /*
1044        * See if this is the toplevel_hidden_dir being archived.
1045        */
1046       if (toplevel_hidden_dir) {
1047          /*
1048           * Save the data for later storage when we encounter a real xattr.
1049           * Encode the stat struct into an ASCII representation and jump out of the function.
1050           */
1051          encode_stat(attribs, &st, 0, stream);
1052          toplevel_hidden_dir_xattr_data_len = snprintf(toplevel_hidden_dir_xattr_data,
1053                                                        sizeof(toplevel_hidden_dir_xattr_data),
1054                                                        "%s%c%s%c%s%c",
1055                                                        target_attrname, 0, attribs, 0,
1056                                                        (acl_text) ? acl_text : "", 0);
1057
1058          goto cleanup;
1059       } else {
1060          /*
1061           * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1062           * Encode the stat struct into an ASCII representation.
1063           */
1064          encode_stat(attribs, &st, 0, stream);
1065          cnt = snprintf(buffer, sizeof(buffer),
1066                         "%s%c%s%c%s%c",
1067                         target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1068       }
1069       break;
1070    case S_IFREG:
1071       /*
1072        * If this is a hardlinked file check the inode cache for a hit.
1073        */
1074       if (st.st_nlink > 1) {
1075          /*
1076           * See if the cache already knows this inode number.
1077           */
1078          if ((xlce = find_xattr_link_cache_entry(st.st_ino)) != NULL) {
1079             /*
1080              * Generate a xattr encoding with the reference to the target in there.
1081              */
1082             encode_stat(attribs, &st, st.st_ino, stream);
1083             cnt = snprintf(buffer, sizeof(buffer),
1084                            "%s%c%s%c%s%c",
1085                            target_attrname, 0, attribs, 0, xlce->target, 0);
1086             pm_memcpy(jcr->xattr_data, buffer, cnt);
1087             jcr->xattr_data_len = cnt;
1088             retval = send_xattr_stream(jcr, stream);
1089
1090             /*
1091              * For a hard linked file we are ready now, no need to recursively archive the attributes.
1092              */
1093             goto cleanup;
1094          }
1095
1096          /*
1097           * Store this hard linked file in the cache.
1098           * Store the name relative to the top level xattr space.
1099           */
1100          add_xattr_link_cache_entry(st.st_ino, target_attrname + 1);
1101       }
1102
1103       /*
1104        * Get any acl on the xattr.
1105        */
1106       if (!solaris_archive_xattr_acl(jcr, attrfd, attrname, &acl_text))
1107          goto cleanup;
1108
1109       /*
1110        * Encode the stat struct into an ASCII representation.
1111        */
1112       encode_stat(attribs, &st, 0, stream);
1113       cnt = snprintf(buffer, sizeof(buffer),
1114                      "%s%c%s%c%s%c",
1115                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1116
1117       /*
1118        * Open the extended or extensible attribute file.
1119        */
1120       if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1121          berrno be;
1122          Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1123             target_attrname, jcr->last_fname, be.bstrerror());
1124          Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1125             target_attrname, jcr->last_fname, be.bstrerror());
1126
1127          goto cleanup;
1128       }
1129       break;
1130    case S_IFLNK:
1131       /*
1132        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1133        * Encode the stat struct into an ASCII representation.
1134        */
1135       if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1136          berrno be;
1137          Jmsg3(jcr, M_ERROR, 0, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1138             target_attrname, jcr->last_fname, be.bstrerror());
1139          Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1140             target_attrname, jcr->last_fname, be.bstrerror());
1141
1142          goto cleanup;
1143       }
1144
1145       /*
1146        * Generate a xattr encoding with the reference to the target in there.
1147        */
1148       encode_stat(attribs, &st, st.st_ino, stream);
1149       cnt = snprintf(buffer, sizeof(buffer),
1150                      "%s%c%s%c%s%c",
1151                      target_attrname, 0, attribs, 0, link_source, 0);
1152       pm_memcpy(jcr->xattr_data, buffer, cnt);
1153       jcr->xattr_data_len = cnt;
1154       retval = send_xattr_stream(jcr, stream);
1155
1156       /*
1157        * For a soft linked file we are ready now, no need to recursively archive the attributes.
1158        */
1159       goto cleanup;
1160    default:
1161       goto cleanup;
1162    }
1163
1164    /*
1165     * See if this is the first real xattr being saved. If it is save the toplevel_hidden_dir attributes first.
1166     */
1167    if (nr_xattr_saved == 0) {
1168       pm_memcpy(jcr->xattr_data, toplevel_hidden_dir_xattr_data, toplevel_hidden_dir_xattr_data_len);
1169       jcr->xattr_data_len = toplevel_hidden_dir_xattr_data_len;
1170       send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1171    }
1172
1173    pm_memcpy(jcr->xattr_data, buffer, cnt);
1174    jcr->xattr_data_len = cnt;
1175
1176    /*
1177     * Only dump the content of regular files.
1178     */
1179    switch (st.st_mode & S_IFMT) {
1180    case S_IFREG:
1181       if (st.st_size > 0) {
1182          /*
1183           * Protect ourself against things getting out of hand.
1184           */
1185          if (st.st_size >= MAX_XATTR_STREAM) {
1186             Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1187                jcr->last_fname, MAX_XATTR_STREAM);
1188
1189             goto cleanup;
1190          }
1191
1192          while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1193             jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, jcr->xattr_data_len + cnt);
1194             memcpy(jcr->xattr_data + jcr->xattr_data_len, buffer, cnt);
1195             jcr->xattr_data_len += cnt;
1196          }
1197
1198          if (cnt < 0) {
1199             Jmsg2(jcr, M_ERROR, 0, _("Unable to read content of xattr %s on file \"%s\"\n"),
1200                target_attrname, jcr->last_fname);
1201             Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1202                target_attrname, jcr->last_fname);
1203
1204             goto cleanup;
1205          }
1206       }
1207       break;
1208    default:
1209       break;
1210    }
1211
1212    retval = send_xattr_stream(jcr, stream);
1213    nr_xattr_saved++;
1214
1215    /*
1216     * Recursivly call solaris_archive_extended_attributes for archiving the attributes
1217     * available on this extended attribute.
1218     */
1219    if (retval) {
1220       retval = solaris_archive_xattrs(jcr, xattr_namespace, attrname);
1221       
1222       /*
1223        * The recursive call could change our working dir so change back to the wanted workdir.
1224        */
1225       if (fchdir(fd) < 0) {
1226          berrno be;
1227          Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1228             jcr->last_fname, be.bstrerror());
1229          Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1230             jcr->last_fname, fd, be.bstrerror());
1231
1232          goto cleanup;
1233       }
1234    }
1235
1236 cleanup:
1237    if (acl_text)
1238       free(acl_text);
1239    if (attrfd != -1)
1240       close(attrfd);
1241
1242    return retval;
1243 }
1244
1245 static bool solaris_archive_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1246 {
1247    const char *name;
1248    int fd, filefd = -1, attrdirfd = -1;
1249    DIR *dirp;
1250    struct dirent *dp;
1251    char current_xattr_namespace[PATH_MAX];
1252    bool retval = false;
1253  
1254    /*
1255     * Determine what argument to use. Use attr_parent when set
1256     * (recursive call) or jcr->last_fname for first call. Also save
1257     * the current depth of the xattr_space we are in.
1258     */
1259    if (attr_parent) {
1260       name = attr_parent;
1261       if (xattr_namespace)
1262          snprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1263                   xattr_namespace, attr_parent);
1264       else
1265          strcpy(current_xattr_namespace, "/");
1266    } else {
1267       name = jcr->last_fname;
1268       strcpy(current_xattr_namespace, "/");
1269    }
1270
1271    /*
1272     * Open the file on which to archive the xattrs read-only.
1273     */
1274    if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1275       berrno be;
1276       Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1277          jcr->last_fname, be.bstrerror());
1278       Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1279          jcr->last_fname, be.bstrerror());
1280
1281       goto cleanup;
1282    }
1283
1284    /*
1285     * Open the xattr naming space.
1286     */
1287    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1288       switch (errno) {
1289       case EINVAL:
1290          /*
1291           * Gentile way of the system saying this type of xattr layering is not supported.
1292           * Which is not problem we just forget about this this xattr.
1293           * But as this is not an error we return a positive return value.
1294           */
1295          retval = true;
1296          break;
1297       default:
1298          berrno be;
1299          Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1300             name, jcr->last_fname, be.bstrerror());
1301          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1302             name, jcr->last_fname, be.bstrerror());
1303       }
1304
1305       goto cleanup;
1306    }
1307
1308   /*
1309    * We need to change into the attribute directory to determine if each of the
1310    * attributes should be archived.
1311    */
1312    if (fchdir(attrdirfd) < 0) {
1313       berrno be;
1314       Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1315          jcr->last_fname, be.bstrerror());
1316       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1317          jcr->last_fname, attrdirfd, be.bstrerror());
1318
1319       goto cleanup;
1320    }
1321
1322    /*
1323     * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1324     * else because the readdir returns "." entry after the extensible attr entry.
1325     * And as we want this entry before anything else we better just save its data.
1326     */
1327    if (!attr_parent)
1328       solaris_archive_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1329                             true, STREAM_XATTR_SOLARIS);
1330
1331    if ((fd = dup(attrdirfd)) == -1 ||
1332        (dirp = fdopendir(fd)) == (DIR *)NULL) {
1333       berrno be;
1334       Jmsg2(jcr, M_ERROR, 0, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1335          jcr->last_fname, be.bstrerror());
1336       Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1337          jcr->last_fname, fd, be.bstrerror());
1338
1339       goto cleanup;
1340    }
1341
1342    /*
1343     * Walk the namespace.
1344     */
1345    while (dp = readdir(dirp)) {
1346       /*
1347        * Skip only the toplevel . dir.
1348        */
1349       if (!attr_parent && !strcmp(dp->d_name, "."))
1350          continue;
1351
1352       /*
1353        * Skip all .. directories
1354        */
1355       if (!strcmp(dp->d_name, ".."))
1356          continue;
1357
1358       Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1359          current_xattr_namespace, dp->d_name, jcr->last_fname);
1360
1361 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1362       /*
1363        * We are not interested in read-only extensible attributes.
1364        */
1365       if (!strcmp(dp->d_name, VIEW_READONLY)) {
1366          Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1367             current_xattr_namespace, dp->d_name, jcr->last_fname);
1368
1369          continue;
1370       }
1371
1372       /*
1373        * We are only interested in read-write extensible attributes
1374        * when they contain non-transient values.
1375        */
1376       if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1377          /*
1378           * Determine if there are non-transient system attributes at the toplevel.
1379           * We need to provide a fd to the open file.
1380           */
1381          if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1382             Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1383                current_xattr_namespace, dp->d_name, jcr->last_fname);
1384
1385             continue;
1386          }
1387
1388          /*
1389           * Archive the xattr.
1390           */
1391          solaris_archive_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1392                                false, STREAM_XATTR_SOLARIS_SYS);
1393          continue;
1394       }
1395 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1396
1397       /*
1398        * Archive the xattr.
1399        */
1400       solaris_archive_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1401                             false, STREAM_XATTR_SOLARIS);
1402    }
1403
1404    closedir(dirp);
1405    retval = true;
1406
1407 cleanup:
1408    if (attrdirfd != -1)
1409       close(attrdirfd);
1410    if (filefd != -1)
1411       close(filefd);
1412
1413    return retval;
1414 }
1415
1416 #ifdef HAVE_ACL
1417 static bool solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1418 {
1419 #ifdef HAVE_EXTENDED_ACL
1420    int error;
1421    acl_t *aclp = NULL;
1422
1423    if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1424       return false;
1425    }
1426
1427    if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1428         acl_set(attrname, aclp) != 0) {
1429       berrno be;
1430       Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1431          attrname, jcr->last_fname, be.bstrerror());
1432       Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1433          attrname, jcr->last_fname, be.bstrerror());
1434
1435       return false;
1436    }
1437
1438    if (aclp)
1439       acl_free(aclp);
1440
1441    return true;
1442 #else /* HAVE_EXTENDED_ACL */
1443    int n;
1444    aclent_t *acls = NULL;
1445
1446    acls = aclfromtext(acl_text, &n);
1447    if (!acls) {
1448       if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1449            acl(attrname, SETACL, n, acls) != 0) {
1450          berrno be;
1451          Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1452             attrname, jcr->last_fname, be.bstrerror());
1453          Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1454             attrname, jcr->last_fname, be.bstrerror());
1455
1456          return false;
1457       }
1458    }
1459
1460    if (acls)
1461       free(acls);
1462
1463    return true;
1464 #endif /* HAVE_EXTENDED_ACL */
1465 }
1466 #endif /* HAVE_ACL */
1467
1468 static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1469 {
1470    int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1471    int used_bytes, total_bytes, cnt;
1472    char *bp, *target_attrname, *attribs;
1473    char *linked_target = NULL;
1474    char *acl_text = NULL;
1475    char *data = NULL;
1476    int32_t inum;
1477    struct stat st;
1478    struct timeval times[2];
1479    bool retval = false;
1480
1481    /*
1482     * Parse the xattr stream. First the part that is the same for all xattrs.
1483     */
1484    used_bytes = 0;
1485    total_bytes = jcr->xattr_data_len;
1486
1487    /*
1488     * The name of the target xattr has a leading / we are not interested
1489     * in that so skip it when decoding the string. We always start a the /
1490     * of the xattr space anyway.
1491     */
1492    target_attrname = jcr->xattr_data + 1;
1493    if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1494        (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1495       goto parse_error;
1496    }
1497    attribs = ++bp;
1498
1499    /*
1500     * Open the file on which to restore the xattrs read-only.
1501     */
1502    if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1503       berrno be;
1504       Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1505          jcr->last_fname, be.bstrerror());
1506       Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1507          jcr->last_fname, be.bstrerror());
1508
1509       goto cleanup;
1510    }
1511
1512    /*
1513     * Open the xattr naming space and make it the current working dir.
1514     */
1515    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1516       berrno be;
1517       Jmsg2(jcr, M_ERROR, 0, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1518          jcr->last_fname, be.bstrerror());
1519       Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1520          jcr->last_fname, be.bstrerror());
1521
1522       goto cleanup;
1523    }
1524
1525    if (fchdir(attrdirfd) < 0) {
1526       berrno be;
1527       Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1528          jcr->last_fname, be.bstrerror());
1529       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1530          jcr->last_fname, attrdirfd, be.bstrerror());
1531
1532       goto cleanup;
1533    }
1534
1535    /*
1536     * Try to open the correct xattr subdir based on the target_attrname given.
1537     * e.g. check if its a subdir attrname. Each / in the string makes us go
1538     * one level deeper.
1539     */
1540    while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1541       *bp = '\0';
1542
1543       if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1544          berrno be;
1545          Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1546             target_attrname, jcr->last_fname, be.bstrerror());
1547          Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1548             target_attrname, jcr->last_fname, be.bstrerror());
1549
1550          goto cleanup;
1551       }
1552
1553       close(filefd);
1554       filefd = fd;
1555
1556       /*
1557        * Open the xattr naming space.
1558        */
1559       if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1560          berrno be;
1561          Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1562             target_attrname, jcr->last_fname, be.bstrerror());
1563          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1564             target_attrname, jcr->last_fname, be.bstrerror());
1565
1566          goto cleanup;
1567       }
1568
1569       close(attrdirfd);
1570       attrdirfd = fd;
1571
1572       /*
1573        * Make the xattr space our current workingdir.
1574        */
1575       if (fchdir(attrdirfd) < 0) {
1576          berrno be;
1577          Jmsg3(jcr, M_ERROR, 0, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1578             target_attrname, jcr->last_fname, be.bstrerror());
1579          Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1580             target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1581
1582          goto cleanup;
1583       }
1584
1585       target_attrname = ++bp;
1586    }
1587
1588    /*
1589     * Decode the attributes from the stream.
1590     */
1591    decode_stat(attribs, &st, &inum);
1592
1593    /*
1594     * Decode the next field (acl_text).
1595     */
1596    if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1597        (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1598       goto parse_error;
1599    }
1600    acl_text = ++bp;
1601
1602    /*
1603     * Based on the filetype perform the correct action. We support most filetypes here, more
1604     * then the actual implementation on Solaris supports so some code may never get executed
1605     * due to limitations in the implementation.
1606     */
1607    switch (st.st_mode & S_IFMT) {
1608    case S_IFIFO:
1609       /*
1610        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1611        */
1612       unlinkat(attrdirfd, target_attrname, 0);
1613       if (mkfifo(target_attrname, st.st_mode) < 0) {
1614          berrno be;
1615          Jmsg3(jcr, M_ERROR, 0, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1616             target_attrname, jcr->last_fname, be.bstrerror());
1617          Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1618             target_attrname,  jcr->last_fname, be.bstrerror());
1619
1620             goto cleanup;
1621       }
1622       break;
1623    case S_IFCHR:
1624    case S_IFBLK:
1625       /*
1626        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1627        */
1628       unlinkat(attrdirfd, target_attrname, 0);
1629       if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1630          berrno be;
1631          Jmsg3(jcr, M_ERROR, 0, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1632             target_attrname, jcr->last_fname, be.bstrerror());
1633          Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1634             target_attrname,  jcr->last_fname, be.bstrerror());
1635
1636          goto cleanup;
1637       }
1638       break;
1639    case S_IFDIR:
1640       /*
1641        * If its not the hidden_dir create the entry.
1642        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1643        */
1644       if (strcmp(target_attrname, ".")) {
1645          unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1646          if (mkdir(target_attrname, st.st_mode) < 0) {
1647             berrno be;
1648             Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1649                target_attrname, jcr->last_fname, be.bstrerror());
1650             Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1651                target_attrname,  jcr->last_fname, be.bstrerror());
1652
1653             goto cleanup;
1654          }
1655       }
1656       break;
1657    case S_IFREG:
1658       /*
1659        * See if this is a hard linked file. e.g. inum != 0
1660        */
1661       if (inum != 0) {
1662          linked_target = bp;
1663
1664          unlinkat(attrdirfd, target_attrname, 0);
1665          if (link(linked_target, target_attrname) < 0) {
1666             berrno be;
1667             Jmsg4(jcr, M_ERROR, 0, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1668                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1669             Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1670                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1671
1672             goto cleanup;
1673          }
1674
1675          /*
1676           * Successfully restored xattr.
1677           */
1678          retval = true;
1679          goto cleanup;
1680       } else {
1681          if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1682              (used_bytes = (bp - jcr->xattr_data)) >= total_bytes) {
1683             goto parse_error;
1684          }
1685
1686          if (used_bytes < (total_bytes - 1))
1687             data = ++bp;
1688
1689          /*
1690           * Restore the actual xattr.
1691           */
1692          if (!is_extensible) {
1693             unlinkat(attrdirfd, target_attrname, 0);
1694          }
1695
1696          if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1697             berrno be;
1698             Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1699                target_attrname, jcr->last_fname, be.bstrerror());
1700             Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1701                target_attrname, jcr->last_fname, be.bstrerror());
1702
1703             goto cleanup;
1704          }
1705       }
1706
1707       /*
1708        * Restore the actual data.
1709        */
1710       if (st.st_size > 0) {
1711          used_bytes = (data - jcr->xattr_data);
1712          cnt = total_bytes - used_bytes;
1713
1714          /*
1715           * Do a sanity check, the st.st_size should be the same as the number of bytes
1716           * we have available as data of the stream.
1717           */
1718          if (cnt != st.st_size) {
1719             Jmsg2(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
1720                target_attrname, jcr->last_fname);
1721             Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1722                target_attrname, jcr->last_fname);
1723
1724             goto cleanup;
1725          }
1726
1727          while (cnt > 0) {
1728             cnt = write(attrfd, data, cnt);
1729             if (cnt < 0) {
1730                berrno be;
1731                Jmsg3(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
1732                   target_attrname, jcr->last_fname, be.bstrerror());
1733                Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
1734                   target_attrname, jcr->last_fname, be.bstrerror());
1735
1736                goto cleanup;
1737             }
1738
1739             used_bytes += cnt;
1740             data += cnt;
1741             cnt = total_bytes - used_bytes;
1742          }
1743       }
1744       break;
1745    case S_IFLNK:
1746       /*
1747        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1748        */
1749       linked_target = bp;
1750
1751       if (symlink(linked_target, target_attrname) < 0) {
1752          berrno be;
1753          Jmsg4(jcr, M_ERROR, 0, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
1754             target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1755          Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
1756             target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1757
1758          goto cleanup;
1759       }
1760
1761       /*
1762        * Successfully restored xattr.
1763        */
1764       retval = true;
1765       goto cleanup;
1766    default:
1767       goto cleanup;
1768    }
1769
1770    /*
1771     * Restore owner and acl for non extensible attributes.
1772     */
1773    if (!is_extensible) {
1774       if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
1775          switch (errno) {
1776          case EINVAL:
1777             /*
1778              * Gentile way of the system saying this type of xattr layering is not supported.
1779              * But as this is not an error we return a positive return value.
1780              */
1781             retval = true;
1782             break;
1783          default:
1784             berrno be;
1785             Jmsg3(jcr, M_ERROR, 0, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1786                target_attrname, jcr->last_fname, be.bstrerror());
1787             Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1788                target_attrname, jcr->last_fname, be.bstrerror());
1789          }
1790
1791          goto cleanup;
1792       }
1793    }
1794
1795 #ifdef HAVE_ACL
1796    if (acl_text && *acl_text)
1797       if (!solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text))
1798          goto cleanup;
1799 #endif /* HAVE_ACL */
1800
1801    /*
1802     * For a non extensible attribute restore access and modification time on the xattr.
1803     */
1804    if (!is_extensible) {
1805       times[0].tv_sec = st.st_atime;
1806       times[0].tv_usec = 0;
1807       times[1].tv_sec = st.st_mtime;
1808       times[1].tv_usec = 0;
1809
1810       if (futimesat(attrdirfd, target_attrname, times) < 0) {
1811          berrno be;
1812          Jmsg3(jcr, M_ERROR, 0, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
1813             target_attrname, jcr->last_fname, be.bstrerror());
1814          Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
1815             target_attrname, jcr->last_fname, be.bstrerror());
1816
1817          goto cleanup;
1818       }
1819    }
1820
1821    /*
1822     * Successfully restored xattr.
1823     */
1824    retval = true;
1825    goto cleanup;
1826
1827 parse_error:
1828    Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
1829       jcr->last_fname);
1830    Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
1831       jcr->last_fname);
1832
1833 cleanup:
1834    if (attrfd != -1)
1835       close(attrfd);
1836    if (attrdirfd != -1)
1837       close(attrdirfd);
1838    if (filefd != -1)
1839       close(filefd);
1840
1841    return retval;
1842 }
1843
1844 static bool solaris_extract_xattr(JCR *jcr, int stream)
1845 {
1846    char cwd[PATH_MAX];
1847    bool is_extensible = false;
1848    bool retval;
1849
1850    /*
1851     * First make sure we can restore xattr on the filesystem.
1852     */
1853    switch (stream) {
1854 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1855    case STREAM_XATTR_SOLARIS_SYS:
1856       if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1857          Qmsg1(jcr, M_WARNING, 0,
1858                _("Failed to restore extensible attributes on file \"%s\"\n"),
1859                jcr->last_fname);
1860          Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1861             jcr->last_fname);
1862
1863          return false;
1864       }
1865
1866       is_extensible = true;
1867       break;
1868 #endif
1869    case STREAM_XATTR_SOLARIS:
1870       if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1871          Qmsg1(jcr, M_WARNING, 0,
1872                _("Failed to restore extended attributes on file \"%s\"\n"),
1873                jcr->last_fname);
1874          Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1875             jcr->last_fname);
1876
1877          return false;
1878       }
1879
1880       break;
1881    default:
1882       return false;
1883    }
1884
1885    /*
1886     * As we change the cwd in the restore function save the current cwd
1887     * for restore after return from the solaris_restore_xattrs function.
1888     */
1889    getcwd(cwd, sizeof(cwd));
1890    retval = solaris_restore_xattrs(jcr, is_extensible);
1891    chdir(cwd);
1892
1893    return retval;
1894 }
1895
1896 static int solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1897 {
1898    char cwd[PATH_MAX];
1899    bool retval = true;
1900
1901    /*
1902     * First see if extended attributes or extensible attributes are present.
1903     * If not just pretend things went ok.
1904     */
1905    if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1906       nr_xattr_saved = 0;
1907
1908       /*
1909        * As we change the cwd in the archive function save the current cwd
1910        * for restore after return from the solaris_archive_xattrs function.
1911        */
1912       getcwd(cwd, sizeof(cwd));
1913       retval = solaris_archive_xattrs(jcr, NULL, NULL);
1914       chdir(cwd);
1915
1916       drop_xattr_link_cache();
1917    }
1918
1919    return retval;
1920 }
1921
1922 static bool solaris_parse_xattr_stream(JCR *jcr, int stream)
1923 {
1924    switch (stream) {
1925 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1926    case STREAM_XATTR_SOLARIS_SYS:
1927 #endif
1928    case STREAM_XATTR_SOLARIS:
1929       return solaris_extract_xattr(jcr, stream);
1930    default:
1931       return false;
1932    }
1933 }
1934 #endif
1935
1936 bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1937 {
1938 #if defined(HAVE_SUN_OS)
1939    return solaris_build_xattr_streams(jcr, ff_pkt);
1940 #elif defined(HAVE_DARWIN_OS)
1941    return darwin_build_xattr_streams(jcr, ff_pkt);
1942 #elif defined(HAVE_FREEBSD_OS)
1943    return freebsd_build_xattr_streams(jcr, ff_pkt);
1944 #elif defined(HAVE_LINUX_OS)
1945    return linux_build_xattr_streams(jcr, ff_pkt);
1946 #elif defined(HAVE_NETBSD_OS)
1947    return netbsd_build_xattr_streams(jcr, ff_pkt);
1948 #endif
1949 }
1950
1951 bool parse_xattr_stream(JCR *jcr, int stream)
1952 {
1953    /*
1954     * Based on the stream being passed in dispatch to the right function
1955     * for parsing and restoring a specific xattr. The platform determines
1956     * which streams are recognized and parsed and which are handled by
1957     * the default case and ignored. As only one of the platform defines
1958     * is true per compile we never end up with duplicate switch values.
1959     */
1960    switch (stream) {
1961 #if defined(HAVE_SUN_OS)
1962 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1963    case STREAM_XATTR_SOLARIS_SYS:
1964 #endif
1965    case STREAM_XATTR_SOLARIS:
1966       return solaris_parse_xattr_stream(jcr, stream);
1967 #elif defined(HAVE_DARWIN_OS)
1968    case STREAM_XATTR_DARWIN:
1969       return darwin_parse_xattr_stream(jcr, stream);
1970 #elif defined(HAVE_FREEBSD_OS)
1971    case STREAM_XATTR_FREEBSD:
1972       return freebsd_parse_xattr_stream(jcr, stream);
1973 #elif defined(HAVE_LINUX_OS)
1974    case STREAM_XATTR_LINUX:
1975       return linux_parse_xattr_stream(jcr, stream);
1976 #elif defined(HAVE_NETBSD_OS)
1977    case STREAM_XATTR_NETBSD:
1978       return netbsd_parse_xattr_stream(jcr, stream);
1979 #endif
1980    default:
1981       /*
1982        * Issue a warning and discard the message. But pretend the restore was ok.
1983        */
1984       Qmsg2(jcr, M_WARNING, 0,
1985          _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1986          jcr->last_fname, stream);
1987       return true;
1988    } /* end switch (stream) */
1989 }
1990
1991 #endif