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