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