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