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