]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/xattr.c
Backport from BEE
[bacula/bacula] / bacula / src / filed / xattr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2008-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /**
17  * Functions to handle Extended Attributes for bacula.
18  *
19  * Extended Attributes are so OS specific we only restore Extended Attributes if
20  * they were saved using a filed on the same platform.
21  *
22  * Currently we support the following OSes:
23  *   - AIX (Extended Attributes)
24  *   - Darwin (Extended Attributes)
25  *   - FreeBSD (Extended Attributes)
26  *   - GNU HURD (Extended Attributes)
27  *   - IRIX (Extended Attributes)
28  *   - Linux (Extended Attributes)
29  *   - NetBSD (Extended Attributes)
30  *   - OpenBSD (Extended Attributes)
31  *     (As it seems either they never implemented xattr or they are removed
32  *      the support as it stated it was in version 3.1 but the current syscall
33  *      tabled shows the extattr_ functions are not implemented. So as such we
34  *      might eventually support xattr on OpenBSD when they implemented them using
35  *      the same interface as FreeBSD and NetBSD.
36  *   - Solaris (Extended Attributes and Extensible Attributes)
37  *   - Tru64 (Extended Attributes)
38  *
39  *   Written by Marco van Wieringen, November 2008
40  *   Major overhaul January 2012 + June 2012
41  */
42
43 #include "bacula.h"
44 #include "filed.h"
45
46 #if !defined(HAVE_XATTR)
47 /**
48  * Entry points when compiled without support for XATTRs or on an unsupported platform.
49  */
50 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
51 {
52    return bxattr_exit_fatal;
53 }
54
55 bxattr_exit_code parse_xattr_streams(JCR *jcr,
56                                      int stream,
57                                      char *content,
58                                      uint32_t content_length)
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->u.build->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->u.build->content);
94    msgsave = sd->msg;
95    sd->msg = jcr->xattr_data->u.build->content;
96    sd->msglen = jcr->xattr_data->u.build->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  * First some generic functions for OSes that use the same xattr encoding scheme.
118  * Currently for all OSes except for Solaris.
119  */
120 #if !defined(HAVE_SUN_OS)
121 static void xattr_drop_internal_table(alist *xattr_value_list)
122 {
123    xattr_t *current_xattr;
124
125    /*
126     * Walk the list of xattrs and free allocated memory on traversing.
127     */
128    foreach_alist(current_xattr, xattr_value_list) {
129       /*
130        * See if we can shortcut.
131        */
132       if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
133          break;
134
135       free(current_xattr->name);
136
137       if (current_xattr->value_length > 0)
138          free(current_xattr->value);
139
140       free(current_xattr);
141    }
142
143    delete xattr_value_list;
144 }
145
146 /**
147  * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
148  * which encodes one or more xattr_t structures.
149  *
150  * The Serialized stream consists of the following elements:
151  *    magic - A magic string which makes it easy to detect any binary incompatabilites
152  *    name_length - The length of the following xattr name
153  *    name - The name of the extended attribute
154  *    value_length - The length of the following xattr data
155  *    value - The actual content of the extended attribute
156  *
157  * This is repeated 1 or more times.
158  *
159  */
160 static uint32_t serialize_xattr_stream(JCR *jcr,
161                                        uint32_t expected_serialize_len,
162                                        alist *xattr_value_list)
163 {
164    xattr_t *current_xattr;
165    ser_declare;
166
167    /*
168     * Make sure the serialized stream fits in the poolmem buffer.
169     * We allocate some more to be sure the stream is gonna fit.
170     */
171    jcr->xattr_data->u.build->content =
172    check_pool_memory_size(jcr->xattr_data->u.build->content,
173                           expected_serialize_len + 10);
174    ser_begin(jcr->xattr_data->u.build->content,
175              expected_serialize_len + 10);
176
177    /*
178     * Walk the list of xattrs and serialize the data.
179     */
180    foreach_alist(current_xattr, xattr_value_list) {
181       /*
182        * See if we can shortcut.
183        */
184       if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
185          break;
186
187       ser_uint32(current_xattr->magic);
188       ser_uint32(current_xattr->name_length);
189       ser_bytes(current_xattr->name, current_xattr->name_length);
190
191       ser_uint32(current_xattr->value_length);
192       if (current_xattr->value_length > 0 && current_xattr->value) {
193          ser_bytes(current_xattr->value, current_xattr->value_length);
194
195          Dmsg3(100, "Backup xattr named %s, value %*s\n",
196                current_xattr->name, current_xattr->value, current_xattr->value);
197       } else {
198          Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
199       }
200    }
201
202    ser_end(jcr->xattr_data->u.build->content, expected_serialize_len + 10);
203    jcr->xattr_data->u.build->content_length =
204    ser_length(jcr->xattr_data->u.build->content);
205
206    return jcr->xattr_data->u.build->content_length;
207 }
208
209 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr,
210                                                  char *content,
211                                                  uint32_t content_length,
212                                                  alist *xattr_value_list)
213 {
214    unser_declare;
215    xattr_t *current_xattr;
216
217    /**
218     * Parse the stream and call restore_xattr_on_file for each extended attribute.
219     *
220     * Start unserializing the data. We keep on looping while we have not
221     * unserialized all bytes in the stream.
222     */
223    unser_begin(content, content_length);
224    while (unser_length(content) < content_length) {
225       /*
226        * First make sure the magic is present. This way we can easily catch corruption.
227        * Any missing MAGIC is fatal we do NOT try to continue.
228        */
229       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
230       unser_uint32(current_xattr->magic);
231       if (current_xattr->magic != XATTR_MAGIC) {
232          Mmsg1(jcr->errmsg,
233                _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
234                jcr->last_fname);
235          Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
236                jcr->last_fname);
237          free(current_xattr);
238          return bxattr_exit_error;
239       }
240
241       /*
242        * Decode the valuepair. First decode the length of the name.
243        */
244       unser_uint32(current_xattr->name_length);
245       if (current_xattr->name_length == 0) {
246          Mmsg1(jcr->errmsg,
247                _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
248                jcr->last_fname);
249          Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
250                jcr->last_fname);
251          free(current_xattr);
252          return bxattr_exit_error;
253       }
254
255       /*
256        * Allocate room for the name and decode its content.
257        */
258       current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
259       unser_bytes(current_xattr->name, current_xattr->name_length);
260
261       /*
262        * The xattr_name needs to be null terminated.
263        */
264       current_xattr->name[current_xattr->name_length] = '\0';
265
266       /*
267        * Decode the value length.
268        */
269       unser_uint32(current_xattr->value_length);
270
271       if (current_xattr->value_length > 0) {
272          /*
273           * Allocate room for the value and decode its content.
274           */
275          current_xattr->value = (char *)malloc(current_xattr->value_length);
276          unser_bytes(current_xattr->value, current_xattr->value_length);
277
278          Dmsg3(100, "Restoring xattr named %s, value %*s\n",
279                current_xattr->name, current_xattr->value, current_xattr->value);
280       } else {
281          current_xattr->value = NULL;
282          Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
283       }
284
285       xattr_value_list->append(current_xattr);
286    }
287
288    unser_end(content, content_length);
289    return bxattr_exit_ok;
290 }
291 #endif
292
293 /*
294  * This is a supported OS, See what kind of interface we should use.
295  */
296 #if defined(HAVE_AIX_OS)
297
298 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
299     (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
300     (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
301 #error "Missing full support for the Extended Attributes (EA) functions."
302 #endif
303
304 #ifdef HAVE_SYS_EA_H
305 #include <sys/ea.h>
306 #else
307 #error "Missing sys/ea.h header file"
308 #endif
309
310 /*
311  * Define the supported XATTR streams for this OS
312  */
313 static int os_default_xattr_streams[1] = {
314    STREAM_XATTR_AIX
315 };
316
317 /*
318  * Fallback to the non l-functions when those are not available.
319  */
320 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
321 #define lgetea getea
322 #endif
323 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
324 #define lsetea setea
325 #endif
326 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
327 #define llistea listea
328 #endif
329
330 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
331 {
332    char *bp;
333    bool skip_xattr;
334    char *xattr_list = NULL;
335    int cnt, xattr_count = 0;
336    uint32_t name_length;
337    int32_t xattr_list_len,
338            xattr_value_len;
339    uint32_t expected_serialize_len = 0;
340    xattr_t *current_xattr;
341    alist *xattr_value_list = NULL;
342    bxattr_exit_code retval = bxattr_exit_error;
343
344    /*
345     * First get the length of the available list with extended attributes.
346     */
347    xattr_list_len = llistea(jcr->last_fname, NULL, 0);
348    switch (xattr_list_len) {
349    case -1: {
350       berrno be;
351
352       switch (errno) {
353       case ENOENT:
354       case EFORMAT:
355          retval = bxattr_exit_ok;
356          goto bail_out;
357       case ENOTSUP:
358          /*
359           * If the filesystem reports it doesn't support XATTRs we clear the
360           * BXATTR_FLAG_SAVE_NATIVE flag so we skip XATTR saves on all other files
361           * on the same filesystem. The BXATTR_FLAG_SAVE_NATIVE flags gets sets again
362           * when we change from one filesystem to an other.
363           */
364          jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
365          retval = bxattr_exit_ok;
366          goto bail_out;
367       default:
368          Mmsg2(jcr->errmsg,
369                _("llistea error on file \"%s\": ERR=%s\n"),
370                jcr->last_fname, be.bstrerror());
371          Dmsg2(100, "llistea error file=%s ERR=%s\n",
372                jcr->last_fname, be.bstrerror());
373          goto bail_out;
374       }
375       break;
376    }
377    case 0:
378       retval = bxattr_exit_ok;
379       goto bail_out;
380    default:
381       break;
382    }
383
384    /*
385     * Allocate room for the extented attribute list.
386     */
387    xattr_list = (char *)malloc(xattr_list_len + 1);
388    memset(xattr_list, 0, xattr_list_len + 1);
389
390    /*
391     * Get the actual list of extended attributes names for a file.
392     */
393    xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
394    switch (xattr_list_len) {
395    case -1: {
396       berrno be;
397
398       switch (errno) {
399       case ENOENT:
400       case EFORMAT:
401          retval = bxattr_exit_ok;
402          goto bail_out;
403       default:
404          Mmsg2(jcr->errmsg,
405                _("llistea error on file \"%s\": ERR=%s\n"),
406                jcr->last_fname, be.bstrerror());
407          Dmsg2(100, "llistea error file=%s ERR=%s\n",
408                jcr->last_fname, be.bstrerror());
409          goto bail_out;
410       }
411       break;
412    }
413    default:
414       break;
415    }
416    xattr_list[xattr_list_len] = '\0';
417
418    /*
419     * Walk the list of extended attributes names and retrieve the data.
420     * We already count the bytes needed for serializing the stream later on.
421     */
422    for (bp = xattr_list;
423        (bp - xattr_list) + 1 < xattr_list_len;
424         bp = strchr(bp, '\0') + 1) {
425       skip_xattr = false;
426
427       /*
428        * We want to skip certain xattrs which start with a 0xF8 character on AIX.
429        */
430       if (*bp == 0xF8) {
431          skip_xattr = true;
432       }
433
434       name_length = strlen(bp);
435       if (skip_xattr || name_length == 0) {
436          Dmsg1(100, "Skipping xattr named %s\n", bp);
437          continue;
438       }
439
440       /*
441        * First see how long the value is for the extended attribute.
442        */
443       xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
444       switch (xattr_value_len) {
445       case -1: {
446          berrno be;
447
448          switch (errno) {
449          case ENOENT:
450          case EFORMAT:
451             retval = bxattr_exit_ok;
452             goto bail_out;
453          default:
454             Mmsg2(jcr->errmsg,
455                   _("lgetea error on file \"%s\": ERR=%s\n"),
456                   jcr->last_fname, be.bstrerror());
457             Dmsg2(100, "lgetea error file=%s ERR=%s\n",
458                   jcr->last_fname, be.bstrerror());
459             goto bail_out;
460          }
461          break;
462       }
463       default:
464          break;
465       }
466
467       /*
468        * Each xattr valuepair starts with a magic so we can parse it easier.
469        */
470       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
471       memset(current_xattr, 0, sizeof(xattr_t));
472       current_xattr->magic = XATTR_MAGIC;
473       expected_serialize_len += sizeof(current_xattr->magic);
474
475       /*
476        * Allocate space for storing the name.
477        */
478       current_xattr->name_length = name_length;
479       current_xattr->name = (char *)malloc(current_xattr->name_length);
480       memcpy(current_xattr->name, bp, current_xattr->name_length);
481
482       expected_serialize_len += sizeof(current_xattr->name_length) +
483                                 current_xattr->name_length;
484
485       switch (xattr_value_len) {
486       case 0:
487          current_xattr->value = NULL;
488          current_xattr->value_length = 0;
489          expected_serialize_len += sizeof(current_xattr->value_length);
490          break;
491       default:
492          /*
493           * Allocate space for storing the value.
494           */
495          current_xattr->value = (char *)malloc(xattr_value_len);
496          memset(current_xattr->value, 0, xattr_value_len);
497
498          xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
499          if (xattr_value_len < 0) {
500             berrno be;
501
502             switch (errno) {
503             case ENOENT:
504             case EFORMAT:
505                retval = bxattr_exit_ok;
506                break;
507             default:
508                Mmsg2(jcr->errmsg,
509                      _("lgetea error on file \"%s\": ERR=%s\n"),
510                      jcr->last_fname, be.bstrerror());
511                Dmsg2(100, "lgetea error file=%s ERR=%s\n",
512                      jcr->last_fname, be.bstrerror());
513                break;
514             }
515
516             /*
517              * Default failure path out when retrieval of attr fails.
518              */
519             free(current_xattr->value);
520             free(current_xattr->name);
521             free(current_xattr);
522             goto bail_out;
523          }
524          /*
525           * Store the actual length of the value.
526           */
527          current_xattr->value_length = xattr_value_len;
528          expected_serialize_len += sizeof(current_xattr->value_length) +
529                                    current_xattr->value_length;
530          break;
531       }
532
533       if (xattr_value_list == NULL) {
534          xattr_value_list = New(alist(10, not_owned_by_alist));
535       }
536
537       xattr_value_list->append(current_xattr);
538       xattr_count++;
539
540       /*
541        * Protect ourself against things getting out of hand.
542        */
543       if (expected_serialize_len >= MAX_XATTR_STREAM) {
544          Mmsg2(jcr->errmsg,
545                _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
546                jcr->last_fname, MAX_XATTR_STREAM);
547          goto bail_out;
548       }
549    }
550
551    free(xattr_list);
552    xattr_list = (char *)NULL;
553
554    /*
555     * If we found any xattr send them to the SD.
556     */
557    if (xattr_count > 0) {
558       /*
559        * Serialize the datastream.
560        */
561       if (serialize_xattr_stream(jcr,
562                                  expected_serialize_len,
563                                  xattr_value_list) < expected_serialize_len) {
564          Mmsg1(jcr->errmsg,
565                _("Failed to serialize extended attributes on file \"%s\"\n"),
566                jcr->last_fname);
567          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
568                jcr->last_fname);
569          goto bail_out;
570       }
571
572       /*
573        * Send the datastream to the SD.
574        */
575       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
576    } else {
577       retval = bxattr_exit_ok;
578    }
579
580 bail_out:
581    if (xattr_list != NULL) {
582       free(xattr_list);
583    }
584    if (xattr_value_list != NULL) {
585       xattr_drop_internal_table(xattr_value_list);
586    }
587
588    return retval;
589 }
590
591 static bxattr_exit_code aix_parse_xattr_streams(JCR *jcr,
592                                                 int stream,
593                                                 char *content,
594                                                 uint32_t content_length)
595 {
596    xattr_t *current_xattr;
597    alist *xattr_value_list;
598    bxattr_exit_code retval = bxattr_exit_error;
599
600    xattr_value_list = New(alist(10, not_owned_by_alist));
601
602    if (unserialize_xattr_stream(jcr,
603                                 content,
604                                 content_length,
605                                 xattr_value_list) != bxattr_exit_ok) {
606       goto bail_out;
607    }
608
609    foreach_alist(current_xattr, xattr_value_list) {
610       if (lsetea(jcr->last_fname,
611                  current_xattr->name,
612                  current_xattr->value,
613                  current_xattr->value_length, 0) != 0) {
614          berrno be;
615
616          switch (errno) {
617          case ENOENT:
618          case EFORMAT:
619             goto bail_out;
620          case ENOTSUP:
621             /*
622              * If the filesystem reports it doesn't support XATTRs we clear
623              * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
624              * on all other files on the same filesystem. The
625              * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
626              * change from one filesystem to an other.
627              */
628             jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
629             goto bail_out;
630          default:
631             Mmsg2(jcr->errmsg,
632                   _("lsetea error on file \"%s\": ERR=%s\n"),
633                   jcr->last_fname, be.bstrerror());
634             Dmsg2(100, "lsetea error file=%s ERR=%s\n",
635                   jcr->last_fname, be.bstrerror());
636             goto bail_out;
637          }
638       }
639    }
640
641    retval = bxattr_exit_ok;
642
643 bail_out:
644    xattr_drop_internal_table(xattr_value_list);
645
646    return retval;
647 }
648
649 /*
650  * Function pointers to the build and parse function to use for these xattrs.
651  */
652 static bxattr_exit_code (*os_build_xattr_streams)
653                         (JCR *jcr, FF_PKT *ff_pkt) =
654                         aix_xattr_build_streams;
655 static bxattr_exit_code (*os_parse_xattr_streams)
656                         (JCR *jcr, int stream, char *content, uint32_t content_length) =
657                         aix_parse_xattr_streams;
658
659 #elif defined(HAVE_IRIX_OS)
660
661 #include <sys/attributes.h>
662
663 /*
664  * Define the supported XATTR streams for this OS
665  */
666 static int os_default_xattr_streams[1] = {
667    STREAM_XATTR_IRIX
668 };
669 static const char *xattr_acl_skiplist[1] = {
670    NULL
671 };
672 static const char *xattr_skiplist[1] = {
673    NULL
674 };
675
676 struct xattr_naming_space {
677    const char *name;
678    int flags;
679 };
680
681 static xattr_naming_space xattr_naming_spaces[] = {
682    {
683       "user.",
684       ATTR_DONTFOLLOW
685    }, {
686       "root.",
687       ATTR_ROOT | ATTR_DONTFOLLOW
688    }, {
689       NULL,
690       0
691    }
692 };
693
694 static bxattr_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
695 {
696    char dummy[32];
697    int cnt, length, xattr_count = 0;
698    attrlist_cursor_t cursor;
699    attrlist_t *attrlist;
700    attrlist_ent_t *attrlist_ent;
701    xattr_t *current_xattr;
702    alist *xattr_value_list = NULL;
703    uint32_t expected_serialize_len = 0;
704    bxattr_exit_code retval = bxattr_exit_error;
705    POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
706
707    for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
708       memset(&cursor, 0, sizeof(attrlist_cursor_t));
709       while (1) {
710          if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
711                        xattr_naming_spaces[cnt].flags, &cursor) != 0) {
712             berrno be;
713
714             switch (errno) {
715             case ENOENT:
716                retval = bxattr_exit_ok;
717                goto bail_out;
718             default:
719                Mmsg2(jcr->errmsg,
720                      _("attr_list error on file \"%s\": ERR=%s\n"),
721                      jcr->last_fname, be.bstrerror());
722                Dmsg2(100, "attr_list error file=%s ERR=%s\n",
723                      jcr->last_fname, be.bstrerror());
724                goto bail_out;
725             }
726          }
727
728          attrlist = (attrlist_t *)xattrbuf;
729
730          /*
731           * Walk the available attributes.
732           */
733          for (cnt = 0; cnt < attrlist->al_count; cnt++) {
734             attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
735
736             /*
737              * First determine if we can retrieve the xattr and how big it really is.
738              */
739             length = sizeof(dummy);
740             if (attr_get(jcr->last_fname, attrlist_ent->a_name, dummy,
741                          &length, xattr_naming_spaces[cnt].flags) != 0) {
742                berrno be;
743
744                switch (errno) {
745                case ENOENT:
746                case ENOATTR:
747                   retval = bxattr_exit_ok;
748                   goto bail_out;
749                case E2BIG:
750                   /*
751                    * Size of the xattr is bigger then the 32 bytes dummy which is
752                    * likely. As length now contains its actual length we can allocate
753                    * a properly size buffer for the real retrieval.
754                    */
755                   break;
756                default:
757                   Mmsg2(jcr->errmsg,
758                         _("attr_list error on file \"%s\": ERR=%s\n"),
759                         jcr->last_fname, be.bstrerror());
760                   Dmsg2(100, "attr_list error file=%s ERR=%s\n",
761                         jcr->last_fname, be.bstrerror());
762                   goto bail_out;
763                }
764             }
765
766             /*
767              * Each xattr valuepair starts with a magic so we can parse it easier.
768              */
769             current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
770             memset(current_xattr, 0, sizeof(xattr_t));
771             current_xattr->magic = XATTR_MAGIC;
772             expected_serialize_len += sizeof(current_xattr->magic);
773
774             /*
775              * Allocate space for storing the name.
776              * We store the name as <naming_space_name><xattr_name>
777              */
778             current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) +
779                                          strlen(attrlist_ent->a_name) + 1;
780             current_xattr->name = (char *)malloc(current_xattr->name_length);
781             bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
782                       xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
783
784             expected_serialize_len += sizeof(current_xattr->name_length) +
785                                       current_xattr->name_length;
786
787             current_xattr->value_length = length;
788             current_xattr->value = (char *)malloc(current_xattr->value_length);
789
790             /*
791              * Retrieve the actual value of the xattr.
792              */
793             if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
794                          &length, xattr_naming_spaces[cnt].flags) != 0) {
795                berrno be;
796
797                switch (errno) {
798                case ENOENT:
799                case ENOATTR:
800                   retval = bxattr_exit_ok;
801                   break;
802                case E2BIG:
803                   /*
804                    * The buffer for the xattr isn't big enough. the value of
805                    * current_xattr->value_length is updated with the actual size
806                    * of the xattr. So we free the old buffer and create a new one
807                    * and try again. Normally this cannot happen as we size the
808                    * buffer using a call to attr_get before but in case of an
809                    * race condition it might happen.
810                    */
811                   free(current_xattr->value);
812                   current_xattr->value = (char *)malloc(length);
813                   if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
814                                &length, xattr_naming_spaces[cnt].flags) != 0) {
815                      switch (errno) {
816                      case ENOENT:
817                      case ENOATTR:
818                         retval = bxattr_exit_ok;
819                         break;
820                      default:
821                         Mmsg2(jcr->errmsg,
822                               _("attr_list error on file \"%s\": ERR=%s\n"),
823                               jcr->last_fname, be.bstrerror(errno));
824                         Dmsg2(100, "attr_list error file=%s ERR=%s\n",
825                               jcr->last_fname, be.bstrerror());
826                         break;
827                      }
828                   } else {
829                      goto ok_continue;
830                   }
831                   break;
832                default:
833                   Mmsg2(jcr->errmsg,
834                         _("attr_list error on file \"%s\": ERR=%s\n"),
835                         jcr->last_fname, be.bstrerror());
836                   Dmsg2(100, "attr_list error file=%s ERR=%s\n",
837                         jcr->last_fname, be.bstrerror());
838                   break;
839                }
840
841                /*
842                 * Default failure path out when retrieval of attr fails.
843                 */
844                free(current_xattr->value);
845                free(current_xattr->name);
846                free(current_xattr);
847                goto bail_out;
848             }
849
850 ok_continue:
851             current_xattr->value_length = length;
852             expected_serialize_len += sizeof(current_xattr->value_length) +
853                                       current_xattr->value_length;
854
855             if (xattr_value_list == NULL) {
856                xattr_value_list = New(alist(10, not_owned_by_alist));
857             }
858
859             xattr_value_list->append(current_xattr);
860             xattr_count++;
861
862             /*
863              * Protect ourself against things getting out of hand.
864              */
865             if (expected_serialize_len >= MAX_XATTR_STREAM) {
866                Mmsg2(jcr->errmsg,
867                      _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
868                      jcr->last_fname, MAX_XATTR_STREAM);
869                goto bail_out;
870             }
871          }
872
873          /*
874           * See if there are more attributes available for a next run of attr_list.
875           */
876          if (attrlist->al_more == 0) {
877             break;
878          }
879       }
880    }
881
882    /*
883     * If we found any xattr send them to the SD.
884     */
885    if (xattr_count > 0) {
886       /*
887        * Serialize the datastream.
888        */
889       if (serialize_xattr_stream(jcr,
890                                  expected_serialize_len,
891                                  xattr_value_list) < expected_serialize_len) {
892          Mmsg1(jcr->errmsg,
893                _("Failed to serialize extended attributes on file \"%s\"\n"),
894                jcr->last_fname);
895          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
896                jcr->last_fname);
897          goto bail_out;
898       }
899
900       /*
901        * Send the datastream to the SD.
902        */
903       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
904    } else {
905       retval = bxattr_exit_ok;
906    }
907
908 bail_out:
909    free_pool_memory(xattrbuf);
910
911    if (xattr_value_list != NULL) {
912       xattr_drop_internal_table(xattr_value_list);
913    }
914
915    return retval;
916 }
917
918 static bxattr_exit_code irix_parse_xattr_streams(JCR *jcr,
919                                                  int stream,
920                                                  char *content,
921                                                  uint32_t content_length)
922 {
923    char *bp;
924    int cnt, cmp_size, name_space_index, flags;
925    xattr_t *current_xattr;
926    alist *xattr_value_list;
927    bxattr_exit_code retval = bxattr_exit_error;
928
929    xattr_value_list = New(alist(10, not_owned_by_alist));
930
931    if (unserialize_xattr_stream(jcr,
932                                 content,
933                                 content_length,
934                                 xattr_value_list) != bxattr_exit_ok) {
935       goto bail_out;
936    }
937
938    foreach_alist(current_xattr, xattr_value_list) {
939       /*
940        * See to what namingspace this xattr belongs to.
941        */
942       name_space_index = 0;
943       for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
944          cmp_size = strlen(xattr_naming_spaces[cnt].name);
945          if (!strncasecmp(current_xattr->name,
946                           xattr_naming_spaces[cnt].name,
947                           cmp_size)) {
948             name_space_index = cnt;
949             break;
950          }
951       }
952
953       /*
954        * If we got a xattr that doesn't belong to an valid namespace complain.
955        */
956       if (name_space_index == 0) {
957          Mmsg2(jcr->errmsg,
958                _("Received illegal xattr named %s on file \"%s\"\n"),
959                current_xattr->name, jcr->last_fname);
960          Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
961                current_xattr->name, jcr->last_fname);
962          goto bail_out;
963       }
964
965       /*
966        * Restore the xattr first try to create the attribute from scratch.
967        */
968       flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
969       bp = strchr(current_xattr->name, '.');
970       if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
971                    current_xattr->value_length, flags) != 0) {
972          berrno be;
973
974          switch (errno) {
975          case ENOENT:
976             retval = bxattr_exit_ok;
977             goto bail_out;
978          case EEXIST:
979             /*
980              * The xattr already exists we need to replace it.
981              */
982             flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
983             if (attr_set(jcr->last_fname, bp, current_xattr->value,
984                          current_xattr->value_length, flags) != 0) {
985                switch (errno) {
986                case ENOENT:
987                   retval = bxattr_exit_ok;
988                   goto bail_out;
989                default:
990                   Mmsg2(jcr->errmsg,
991                         _("attr_set error on file \"%s\": ERR=%s\n"),
992                         jcr->last_fname, be.bstrerror(errno));
993                   Dmsg2(100, "attr_set error file=%s ERR=%s\n",
994                         jcr->last_fname, be.bstrerror());
995                   goto bail_out;
996                }
997             }
998             break;
999          default:
1000             Mmsg2(jcr->errmsg,
1001                   _("attr_set error on file \"%s\": ERR=%s\n"),
1002                   jcr->last_fname, be.bstrerror());
1003             Dmsg2(100, "attr_set error file=%s ERR=%s\n",
1004                   jcr->last_fname, be.bstrerror());
1005             goto bail_out;
1006          }
1007       }
1008    }
1009
1010    retval = bxattr_exit_ok;
1011
1012 bail_out:
1013    xattr_drop_internal_table(xattr_value_list);
1014
1015    return retval;
1016 }
1017
1018 /*
1019  * Function pointers to the build and parse function to use for these xattrs.
1020  */
1021 static bxattr_exit_code (*os_build_xattr_streams)
1022                         (JCR *jcr, FF_PKT *ff_pkt) =
1023                         irix_xattr_build_streams;
1024 static bxattr_exit_code (*os_parse_xattr_streams)
1025                         (JCR *jcr, int stream, char *content, uint32_t content_length) =
1026                         irix_parse_xattr_streams;
1027
1028 #elif defined(HAVE_DARWIN_OS) || \
1029       defined(HAVE_LINUX_OS) || \
1030       defined(HAVE_HURD_OS)
1031
1032 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
1033     (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
1034     (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
1035 #error "Missing full support for the XATTR functions."
1036 #endif
1037
1038 #ifdef HAVE_SYS_XATTR_H
1039 #include <sys/xattr.h>
1040 #else
1041 #error "Missing sys/xattr.h header file"
1042 #endif
1043
1044 /*
1045  * Define the supported XATTR streams for this OS
1046  */
1047 #if defined(HAVE_DARWIN_OS)
1048 static int os_default_xattr_streams[1] = {
1049    STREAM_XATTR_DARWIN
1050 };
1051 static const char *xattr_acl_skiplist[2] = {
1052    "com.apple.system.Security",
1053    NULL
1054 };
1055 static const char *xattr_skiplist[3] = {
1056    "com.apple.system.extendedsecurity",
1057    "com.apple.ResourceFork",
1058    NULL
1059 };
1060 #elif defined(HAVE_LINUX_OS)
1061 static int os_default_xattr_streams[1] = {
1062    STREAM_XATTR_LINUX
1063 };
1064 static const char *xattr_acl_skiplist[3] = {
1065    "system.posix_acl_access",
1066    "system.posix_acl_default",
1067    NULL
1068 };
1069 static const char *xattr_skiplist[1] = {
1070    NULL
1071 };
1072 #elif defined(HAVE_HURD_OS)
1073 static int os_default_xattr_streams[1] = {
1074    STREAM_XATTR_HURD
1075 };
1076 static const char *xattr_acl_skiplist[1] = {
1077    NULL
1078 };
1079 static const char *xattr_skiplist[1] = {
1080    NULL
1081 };
1082 #endif
1083
1084 /*
1085  * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
1086  * listxattr, getxattr and setxattr with an extra options argument
1087  * which mimics the l variants of the functions when we specify
1088  * XATTR_NOFOLLOW as the options value.
1089  */
1090 #if defined(HAVE_DARWIN_OS)
1091    #define llistxattr(path, list, size) \
1092            listxattr((path), (list), (size), XATTR_NOFOLLOW)
1093    #define lgetxattr(path, name, value, size) \
1094            getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
1095    #define lsetxattr(path, name, value, size, flags) \
1096            setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
1097 #else
1098    /*
1099     * Fallback to the non l-functions when those are not available.
1100     */
1101    #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
1102    #define lgetxattr getxattr
1103    #endif
1104    #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
1105    #define lsetxattr setxattr
1106    #endif
1107    #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
1108    #define llistxattr listxattr
1109    #endif
1110 #endif
1111
1112 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
1113 {
1114    char *bp;
1115    bool skip_xattr;
1116    char *xattr_list = NULL;
1117    int cnt, xattr_count = 0;
1118    uint32_t name_length;
1119    int32_t xattr_list_len,
1120            xattr_value_len;
1121    uint32_t expected_serialize_len = 0;
1122    xattr_t *current_xattr;
1123    alist *xattr_value_list = NULL;
1124    bxattr_exit_code retval = bxattr_exit_error;
1125
1126    /*
1127     * First get the length of the available list with extended attributes.
1128     */
1129    xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
1130    switch (xattr_list_len) {
1131    case -1: {
1132       berrno be;
1133
1134       switch (errno) {
1135       case ENOENT:
1136          retval = bxattr_exit_ok;
1137          goto bail_out;
1138       case BXATTR_ENOTSUP:
1139          /*
1140           * If the filesystem reports it doesn't support XATTRs we clear
1141           * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1142           * on all other files on the same filesystem. The
1143           * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1144           * change from one filesystem to an other.
1145           */
1146          jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1147          retval = bxattr_exit_ok;
1148          goto bail_out;
1149       default:
1150          Mmsg2(jcr->errmsg,
1151                _("llistxattr error on file \"%s\": ERR=%s\n"),
1152                jcr->last_fname, be.bstrerror());
1153          Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1154                jcr->last_fname, be.bstrerror());
1155          goto bail_out;
1156       }
1157       break;
1158    }
1159    case 0:
1160       retval = bxattr_exit_ok;
1161       goto bail_out;
1162    default:
1163       break;
1164    }
1165
1166    /*
1167     * Allocate room for the extented attribute list.
1168     */
1169    xattr_list = (char *)malloc(xattr_list_len + 1);
1170    memset(xattr_list, 0, xattr_list_len + 1);
1171
1172    /*
1173     * Get the actual list of extended attributes names for a file.
1174     */
1175    xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
1176    switch (xattr_list_len) {
1177    case -1: {
1178       berrno be;
1179
1180       switch (errno) {
1181       case ENOENT:
1182          retval = bxattr_exit_ok;
1183          goto bail_out;
1184       default:
1185          Mmsg2(jcr->errmsg,
1186                _("llistxattr error on file \"%s\": ERR=%s\n"),
1187                jcr->last_fname, be.bstrerror());
1188          Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1189                jcr->last_fname, be.bstrerror());
1190          goto bail_out;
1191       }
1192       break;
1193    }
1194    default:
1195       break;
1196    }
1197    xattr_list[xattr_list_len] = '\0';
1198
1199    /*
1200     * Walk the list of extended attributes names and retrieve the data.
1201     * We already count the bytes needed for serializing the stream later on.
1202     */
1203    for (bp = xattr_list;
1204        (bp - xattr_list) + 1 < xattr_list_len;
1205         bp = strchr(bp, '\0') + 1) {
1206       skip_xattr = false;
1207
1208       /*
1209        * On some OSes you also get the acls in the extented attribute list.
1210        * So we check if we are already backing up acls and if we do we
1211        * don't store the extended attribute with the same info.
1212        */
1213       if (ff_pkt->flags & FO_ACL) {
1214          for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1215             if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1216                skip_xattr = true;
1217                break;
1218             }
1219          }
1220       }
1221
1222       /*
1223        * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1224        */
1225       if (!skip_xattr) {
1226          for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1227             if (bstrcmp(bp, xattr_skiplist[cnt])) {
1228                skip_xattr = true;
1229                break;
1230             }
1231          }
1232       }
1233
1234       name_length = strlen(bp);
1235       if (skip_xattr || name_length == 0) {
1236          Dmsg1(100, "Skipping xattr named %s\n", bp);
1237          continue;
1238       }
1239
1240       /*
1241        * First see how long the value is for the extended attribute.
1242        */
1243       xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1244       switch (xattr_value_len) {
1245       case -1: {
1246          berrno be;
1247
1248          switch (errno) {
1249          case ENOENT:
1250             retval = bxattr_exit_ok;
1251             goto bail_out;
1252          default:
1253             Mmsg2(jcr->errmsg,
1254                   _("lgetxattr error on file \"%s\": ERR=%s\n"),
1255                   jcr->last_fname, be.bstrerror());
1256             Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1257                   jcr->last_fname, be.bstrerror());
1258             goto bail_out;
1259          }
1260          break;
1261       }
1262       default:
1263          break;
1264       }
1265
1266       /*
1267        * Each xattr valuepair starts with a magic so we can parse it easier.
1268        */
1269       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1270       current_xattr->magic = XATTR_MAGIC;
1271       current_xattr->value = NULL;
1272       expected_serialize_len += sizeof(current_xattr->magic);
1273
1274       /*
1275        * Allocate space for storing the name.
1276        */
1277       current_xattr->name_length = name_length;
1278       current_xattr->name = (char *)malloc(current_xattr->name_length);
1279       memcpy(current_xattr->name, bp, current_xattr->name_length);
1280
1281       expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1282
1283       switch (xattr_value_len) {
1284       case 0:
1285          current_xattr->value = NULL;
1286          current_xattr->value_length = 0;
1287          expected_serialize_len += sizeof(current_xattr->value_length);
1288          break;
1289       default:
1290          /*
1291           * Allocate space for storing the value.
1292           */
1293          current_xattr->value = (char *)malloc(xattr_value_len);
1294          memset(current_xattr->value, 0, xattr_value_len);
1295
1296          xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1297          if (xattr_value_len < 0) {
1298             berrno be;
1299
1300             switch (errno) {
1301             case ENOENT:
1302                retval = bxattr_exit_ok;
1303                break;
1304             default:
1305                Mmsg2(jcr->errmsg,
1306                      _("lgetxattr error on file \"%s\": ERR=%s\n"),
1307                      jcr->last_fname, be.bstrerror());
1308                Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1309                      jcr->last_fname, be.bstrerror());
1310                break;
1311             }
1312
1313             /*
1314              * Default failure path out when retrieval of attr fails.
1315              */
1316             free(current_xattr->value);
1317             free(current_xattr->name);
1318             free(current_xattr);
1319             goto bail_out;
1320          }
1321
1322          /*
1323           * Store the actual length of the value.
1324           */
1325          current_xattr->value_length = xattr_value_len;
1326          expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1327          break;
1328       }
1329
1330       if (xattr_value_list == NULL) {
1331          xattr_value_list = New(alist(10, not_owned_by_alist));
1332       }
1333
1334       xattr_value_list->append(current_xattr);
1335       xattr_count++;
1336
1337       /*
1338        * Protect ourself against things getting out of hand.
1339        */
1340       if (expected_serialize_len >= MAX_XATTR_STREAM) {
1341          Mmsg2(jcr->errmsg,
1342                _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1343                jcr->last_fname, MAX_XATTR_STREAM);
1344          goto bail_out;
1345       }
1346    }
1347
1348    free(xattr_list);
1349    xattr_list = (char *)NULL;
1350
1351    /*
1352     * If we found any xattr send them to the SD.
1353     */
1354    if (xattr_count > 0) {
1355       /*
1356        * Serialize the datastream.
1357        */
1358       if (serialize_xattr_stream(jcr,
1359                                  expected_serialize_len,
1360                                  xattr_value_list) < expected_serialize_len) {
1361          Mmsg1(jcr->errmsg,
1362                _("Failed to serialize extended attributes on file \"%s\"\n"),
1363                jcr->last_fname);
1364          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1365                jcr->last_fname);
1366          goto bail_out;
1367       }
1368
1369       /*
1370        * Send the datastream to the SD.
1371        */
1372       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1373    } else {
1374       retval = bxattr_exit_ok;
1375    }
1376
1377 bail_out:
1378    if (xattr_list != NULL) {
1379       free(xattr_list);
1380    }
1381    if (xattr_value_list != NULL) {
1382       xattr_drop_internal_table(xattr_value_list);
1383    }
1384
1385    return retval;
1386 }
1387
1388 static bxattr_exit_code generic_parse_xattr_streams(JCR *jcr,
1389                                                     int stream,
1390                                                     char *content,
1391                                                     uint32_t content_length)
1392 {
1393    xattr_t *current_xattr;
1394    alist *xattr_value_list;
1395    bxattr_exit_code retval = bxattr_exit_error;
1396
1397    xattr_value_list = New(alist(10, not_owned_by_alist));
1398
1399    if (unserialize_xattr_stream(jcr,
1400                                 content,
1401                                 content_length,
1402                                 xattr_value_list) != bxattr_exit_ok) {
1403       goto bail_out;
1404    }
1405
1406    foreach_alist(current_xattr, xattr_value_list) {
1407       if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1408          berrno be;
1409
1410          switch (errno) {
1411          case ENOENT:
1412             goto bail_out;
1413          case BXATTR_ENOTSUP:
1414             /*
1415              * If the filesystem reports it doesn't support XATTRs we clear
1416              * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1417              * on all other files on the same filesystem. The
1418              * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1419              * change from one filesystem to an other.
1420              */
1421             jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
1422             goto bail_out;
1423          default:
1424             Mmsg2(jcr->errmsg,
1425                   _("lsetxattr error on file \"%s\": ERR=%s\n"),
1426                   jcr->last_fname, be.bstrerror());
1427             Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1428                   jcr->last_fname, be.bstrerror());
1429             goto bail_out;
1430          }
1431       }
1432    }
1433
1434    retval = bxattr_exit_ok;
1435
1436 bail_out:
1437    xattr_drop_internal_table(xattr_value_list);
1438
1439    return retval;
1440 }
1441
1442 /*
1443  * Function pointers to the build and parse function to use for these xattrs.
1444  */
1445 static bxattr_exit_code (*os_build_xattr_streams)
1446                         (JCR *jcr, FF_PKT *ff_pkt) =
1447                         generic_xattr_build_streams;
1448 static bxattr_exit_code (*os_parse_xattr_streams)
1449                         (JCR *jcr, int stream, char *content, uint32_t content_length) =
1450                         generic_parse_xattr_streams;
1451
1452 #elif defined(HAVE_FREEBSD_OS) || \
1453       defined(HAVE_NETBSD_OS) || \
1454       defined(HAVE_OPENBSD_OS)
1455
1456 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1457     (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1458     (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1459     !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1460     !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1461 #error "Missing full support for the extattr functions."
1462 #endif
1463
1464 #ifdef HAVE_SYS_EXTATTR_H
1465 #include <sys/extattr.h>
1466 #else
1467 #error "Missing sys/extattr.h header file"
1468 #endif
1469
1470 #ifdef HAVE_LIBUTIL_H
1471 #include <libutil.h>
1472 #endif
1473
1474 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1475 #define extattr_get_link extattr_get_file
1476 #endif
1477 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1478 #define extattr_set_link extattr_set_file
1479 #endif
1480 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1481 #define extattr_list_link extattr_list_file
1482 #endif
1483
1484 #if defined(HAVE_FREEBSD_OS)
1485 static int os_default_xattr_streams[1] = {
1486    STREAM_XATTR_FREEBSD
1487 };
1488 static int os_default_xattr_namespaces[2] = {
1489    EXTATTR_NAMESPACE_USER,
1490    EXTATTR_NAMESPACE_SYSTEM
1491 };
1492 static const char *xattr_acl_skiplist[4] = {
1493    "system.posix1e.acl_access",
1494    "system.posix1e.acl_default",
1495    "system.nfs4.acl",
1496    NULL
1497 };
1498 static const char *xattr_skiplist[1] = {
1499    NULL
1500 };
1501 #elif defined(HAVE_NETBSD_OS)
1502 static int os_default_xattr_streams[1] = {
1503    STREAM_XATTR_NETBSD
1504 };
1505 static int os_default_xattr_namespaces[2] = {
1506    EXTATTR_NAMESPACE_USER,
1507    EXTATTR_NAMESPACE_SYSTEM
1508 };
1509 static const char *xattr_acl_skiplist[1] = {
1510    NULL
1511 };
1512 static const char *xattr_skiplist[1] = {
1513    NULL
1514 };
1515 #elif defined(HAVE_OPENBSD_OS)
1516 static int os_default_xattr_streams[1] = {
1517    STREAM_XATTR_OPENBSD
1518 };
1519 static int os_default_xattr_namespaces[2] = {
1520    EXTATTR_NAMESPACE_USER,
1521    EXTATTR_NAMESPACE_SYSTEM
1522 };
1523 static const char *xattr_acl_skiplist[1] = {
1524    NULL
1525 };
1526 static const char *xattr_skiplist[1] = {
1527    NULL
1528 };
1529 #endif
1530
1531 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1532 {
1533    bool skip_xattr;
1534    char *xattr_list = NULL;
1535    int cnt, index, xattr_count = 0;
1536    int32_t xattr_list_len,
1537            xattr_value_len;
1538    uint32_t expected_serialize_len = 0;
1539    unsigned int namespace_index;
1540    int attrnamespace;
1541    char *current_attrnamespace = NULL;
1542    char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1543    xattr_t *current_xattr;
1544    alist *xattr_value_list = NULL;
1545    bxattr_exit_code retval = bxattr_exit_error;
1546
1547    /*
1548     * Loop over all available xattr namespaces.
1549     */
1550    for (namespace_index = 0;
1551         namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int);
1552         namespace_index++) {
1553       attrnamespace = os_default_xattr_namespaces[namespace_index];
1554
1555       /*
1556        * First get the length of the available list with extended attributes.
1557        * If we get EPERM on system namespace, don't return error.
1558        * This is expected for normal users trying to archive the system
1559        * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1560        * they've decided to return EOPNOTSUPP instead.
1561        */
1562       xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1563       switch (xattr_list_len) {
1564       case -1: {
1565          berrno be;
1566
1567          switch (errno) {
1568          case ENOENT:
1569             retval = bxattr_exit_ok;
1570             goto bail_out;
1571 #if defined(EOPNOTSUPP)
1572          case EOPNOTSUPP:
1573 #endif
1574          case EPERM:
1575             if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1576                continue;
1577             }
1578             /*
1579              * FALLTHROUGH
1580              */
1581          default:
1582             Mmsg2(jcr->errmsg,
1583                   _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1584                   jcr->last_fname, be.bstrerror());
1585             Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1586                   jcr->last_fname, be.bstrerror());
1587             goto bail_out;
1588          }
1589          break;
1590       }
1591       case 0:
1592          continue;
1593       default:
1594          break;
1595       }
1596
1597       /*
1598        * Allocate room for the extented attribute list.
1599        */
1600       xattr_list = (char *)malloc(xattr_list_len + 1);
1601       memset(xattr_list, 0, xattr_list_len + 1);
1602
1603       /*
1604        * Get the actual list of extended attributes names for a file.
1605        */
1606       xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace,
1607                                          xattr_list, xattr_list_len);
1608       switch (xattr_list_len) {
1609       case -1: {
1610          berrno be;
1611
1612          switch (errno) {
1613          case ENOENT:
1614             retval = bxattr_exit_ok;
1615             goto bail_out;
1616          default:
1617             Mmsg2(jcr->errmsg,
1618                   _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1619                   jcr->last_fname, be.bstrerror());
1620             Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1621                   jcr->last_fname, be.bstrerror());
1622             goto bail_out;
1623          }
1624          break;
1625       }
1626       default:
1627          break;
1628       }
1629       xattr_list[xattr_list_len] = '\0';
1630
1631       /*
1632        * Convert the numeric attrnamespace into a string representation and make
1633        * a private copy of that string. The extattr_namespace_to_string functions
1634        * returns a strdupped string which we need to free.
1635        */
1636       if (extattr_namespace_to_string(attrnamespace, &current_attrnamespace) != 0) {
1637          Mmsg2(jcr->errmsg,
1638                _("Failed to convert %d into namespace on file \"%s\"\n"),
1639                attrnamespace, jcr->last_fname);
1640          Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1641                attrnamespace, jcr->last_fname);
1642          goto bail_out;
1643       }
1644
1645       /*
1646        * Walk the list of extended attributes names and retrieve the data.
1647        * We already count the bytes needed for serializing the stream later on.
1648        */
1649       for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1650          skip_xattr = false;
1651
1652          /*
1653           * Print the current name into the buffer as its not null terminated
1654           * we need to use the length encoded in the string for copying only
1655           * the needed bytes.
1656           */
1657          cnt = xattr_list[index];
1658          if (cnt > ((int)sizeof(current_attrname) - 1)) {
1659             cnt = ((int)sizeof(current_attrname) - 1);
1660          }
1661          strncpy(current_attrname, xattr_list + (index + 1), cnt);
1662          current_attrname[cnt] = '\0';
1663
1664          /*
1665           * First make a xattr tuple of the current namespace and the name of
1666           * the xattr. e.g. something like user.<attrname> or system.<attrname>
1667           */
1668          bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s",
1669                    current_attrnamespace, current_attrname);
1670
1671          /*
1672           * On some OSes you also get the acls in the extented attribute list.
1673           * So we check if we are already backing up acls and if we do we
1674           * don't store the extended attribute with the same info.
1675           */
1676          if (ff_pkt->flags & FO_ACL) {
1677             for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1678                if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1679                   skip_xattr = true;
1680                   break;
1681                }
1682             }
1683          }
1684
1685          /*
1686           * On some OSes we want to skip certain xattrs which are in the
1687           * xattr_skiplist array.
1688           */
1689          if (!skip_xattr) {
1690             for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1691                if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1692                   skip_xattr = true;
1693                   break;
1694                }
1695             }
1696          }
1697
1698          if (skip_xattr) {
1699             Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1700             continue;
1701          }
1702
1703          /*
1704           * First see how long the value is for the extended attribute.
1705           */
1706          xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1707                                             current_attrname, NULL, 0);
1708          switch (xattr_value_len) {
1709          case -1: {
1710             berrno be;
1711
1712             switch (errno) {
1713             case ENOENT:
1714                retval = bxattr_exit_ok;
1715                goto bail_out;
1716             default:
1717                Mmsg2(jcr->errmsg,
1718                      _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1719                      jcr->last_fname, be.bstrerror());
1720                Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1721                      jcr->last_fname, be.bstrerror());
1722                goto bail_out;
1723             }
1724             break;
1725          }
1726          default:
1727             break;
1728          }
1729
1730          /*
1731           * Each xattr valuepair starts with a magic so we can parse it easier.
1732           */
1733          current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1734          memset(current_xattr, 0, sizeof(xattr_t));
1735          current_xattr->magic = XATTR_MAGIC;
1736          expected_serialize_len += sizeof(current_xattr->magic);
1737
1738          /*
1739           * Allocate space for storing the name.
1740           */
1741          current_xattr->name_length = strlen(current_attrtuple);
1742          current_xattr->name = (char *)malloc(current_xattr->name_length);
1743          memcpy(current_xattr->name, current_attrtuple, current_xattr->name_length);
1744
1745          expected_serialize_len += sizeof(current_xattr->name_length) +
1746                                    current_xattr->name_length;
1747
1748          switch (xattr_value_len) {
1749          case 0:
1750             current_xattr->value = NULL;
1751             current_xattr->value_length = 0;
1752             expected_serialize_len += sizeof(current_xattr->value_length);
1753             break;
1754          default:
1755             /*
1756              * Allocate space for storing the value.
1757              */
1758             current_xattr->value = (char *)malloc(xattr_value_len);
1759             memset(current_xattr->value, 0, xattr_value_len);
1760
1761             xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1762                                                current_attrname, current_xattr->value,
1763                                                xattr_value_len);
1764             if (xattr_value_len < 0) {
1765                berrno be;
1766
1767                switch (errno) {
1768                case ENOENT:
1769                   retval = bxattr_exit_ok;
1770                   break;
1771                default:
1772                   Mmsg2(jcr->errmsg,
1773                         _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1774                         jcr->last_fname, be.bstrerror());
1775                   Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1776                         jcr->last_fname, be.bstrerror());
1777                   break;
1778                }
1779
1780                /*
1781                 * Default failure path out when retrieval of attr fails.
1782                 */
1783                free(current_xattr->value);
1784                free(current_xattr->name);
1785                free(current_xattr);
1786                goto bail_out;
1787             }
1788
1789             /*
1790              * Store the actual length of the value.
1791              */
1792             current_xattr->value_length = xattr_value_len;
1793             expected_serialize_len += sizeof(current_xattr->value_length) +
1794                                       current_xattr->value_length;
1795             break;
1796          }
1797
1798          if (xattr_value_list == NULL) {
1799             xattr_value_list = New(alist(10, not_owned_by_alist));
1800          }
1801
1802          xattr_value_list->append(current_xattr);
1803          xattr_count++;
1804
1805          /*
1806           * Protect ourself against things getting out of hand.
1807           */
1808          if (expected_serialize_len >= MAX_XATTR_STREAM) {
1809             Mmsg2(jcr->errmsg,
1810                   _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1811                   jcr->last_fname, MAX_XATTR_STREAM);
1812             goto bail_out;
1813          }
1814       }
1815
1816       /*
1817        * Drop the local copy of the current_attrnamespace.
1818        */
1819       actuallyfree(current_attrnamespace);
1820       current_attrnamespace = NULL;
1821
1822       /*
1823        * We are done with this xattr list.
1824        */
1825       free(xattr_list);
1826       xattr_list = (char *)NULL;
1827    }
1828
1829    /*
1830     * If we found any xattr send them to the SD.
1831     */
1832    if (xattr_count > 0) {
1833       /*
1834        * Serialize the datastream.
1835        */
1836       if (serialize_xattr_stream(jcr,
1837                                  expected_serialize_len,
1838                                  xattr_value_list) < expected_serialize_len) {
1839          Mmsg1(jcr->errmsg,
1840                _("Failed to serialize extended attributes on file \"%s\"\n"),
1841                jcr->last_fname);
1842          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1843                jcr->last_fname);
1844          goto bail_out;
1845       }
1846
1847       /*
1848        * Send the datastream to the SD.
1849        */
1850       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1851    } else {
1852       retval = bxattr_exit_ok;
1853    }
1854
1855 bail_out:
1856    if (current_attrnamespace != NULL) {
1857       actuallyfree(current_attrnamespace);
1858    }
1859    if (xattr_list != NULL) {
1860       free(xattr_list);
1861    }
1862    if (xattr_value_list != NULL) {
1863       xattr_drop_internal_table(xattr_value_list);
1864    }
1865
1866    return retval;
1867 }
1868
1869 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr,
1870                                                 int stream,
1871                                                 char *content,
1872                                                 uint32_t content_length)
1873 {
1874    xattr_t *current_xattr;
1875    alist *xattr_value_list;
1876    int current_attrnamespace, cnt;
1877    char *attrnamespace, *attrname;
1878    bxattr_exit_code retval = bxattr_exit_error;
1879
1880    xattr_value_list = New(alist(10, not_owned_by_alist));
1881
1882    if (unserialize_xattr_stream(jcr,
1883                                 content,
1884                                 content_length,
1885                                 xattr_value_list) != bxattr_exit_ok) {
1886       goto bail_out;
1887    }
1888
1889    foreach_alist(current_xattr, xattr_value_list) {
1890       /*
1891        * Try splitting the xattr_name into a namespace and name part.
1892        * The splitting character is a .
1893        */
1894       attrnamespace = current_xattr->name;
1895       if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1896          Mmsg2(jcr->errmsg,
1897                _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1898                current_xattr->name, jcr->last_fname);
1899          Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1900                current_xattr->name, jcr->last_fname);
1901          goto bail_out;
1902       }
1903       *attrname++ = '\0';
1904
1905       /*
1906        * Make sure the attrnamespace makes sense.
1907        */
1908       if (extattr_string_to_namespace(attrnamespace, &current_attrnamespace) != 0) {
1909          Mmsg2(jcr->errmsg,
1910                _("Failed to convert %s into namespace on file \"%s\"\n"),
1911                attrnamespace, jcr->last_fname);
1912          Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1913                attrnamespace, jcr->last_fname);
1914          goto bail_out;
1915       }
1916
1917       /*
1918        * Try restoring the extended attribute.
1919        */
1920       cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1921                              attrname, current_xattr->value, current_xattr->value_length);
1922       if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1923          berrno be;
1924
1925          switch (errno) {
1926          case ENOENT:
1927             goto bail_out;
1928             break;
1929          default:
1930             Mmsg2(jcr->errmsg,
1931                   _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1932                   jcr->last_fname, be.bstrerror());
1933             Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1934                   jcr->last_fname, be.bstrerror());
1935             goto bail_out;
1936             break;
1937          }
1938       }
1939    }
1940
1941    retval = bxattr_exit_ok;
1942
1943 bail_out:
1944    xattr_drop_internal_table(xattr_value_list);
1945
1946    return retval;
1947 }
1948
1949 /*
1950  * Function pointers to the build and parse function to use for these xattrs.
1951  */
1952 static bxattr_exit_code (*os_build_xattr_streams)
1953                         (JCR *jcr, FF_PKT *ff_pkt) =
1954                         bsd_build_xattr_streams;
1955 static bxattr_exit_code (*os_parse_xattr_streams)
1956                         (JCR *jcr, int stream, char *content, uint32_t content_length) =
1957                         bsd_parse_xattr_streams;
1958
1959 #elif defined(HAVE_OSF1_OS)
1960
1961 #if !defined(HAVE_GETPROPLIST) || \
1962     !defined(HAVE_GET_PROPLIST_ENTRY) || \
1963     !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1964     !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1965     !defined(HAVE_SETPROPLIST)
1966 #error "Missing full support for the Extended Attributes functions."
1967 #endif
1968
1969 #ifdef HAVE_SYS_PROPLIST_H
1970 #include <sys/proplist.h>
1971 #else
1972 #error "Missing sys/proplist.h header file"
1973 #endif
1974
1975 /*
1976  * Define the supported XATTR streams for this OS
1977  */
1978 static int os_default_xattr_streams[1] = {
1979    STREAM_XATTR_TRU64
1980 };
1981 static const char *xattr_acl_skiplist[1] = {
1982    NULL
1983 };
1984 static const char *xattr_skiplist[1] = {
1985    NULL
1986 };
1987
1988 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1989 {
1990    int cnt;
1991    char *bp,
1992         *xattr_name,
1993         *xattr_value;
1994    bool skip_xattr;
1995    int xattr_count = 0;
1996    int32_t *flags,
1997            *xattr_value_len;
1998    int32_t xattr_list_len,
1999            xattrbuf_size,
2000            xattrbuf_min_size;
2001    uint32_t expected_serialize_len = 0;
2002    xattr_t *current_xattr;
2003    alist *xattr_value_list = NULL;
2004    struct proplistname_args prop_args;
2005    bxattr_exit_code retval = bxattr_exit_error;
2006    POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
2007
2008    xattrbuf_size = sizeof_pool_memory(xattrbuf);
2009    xattrbuf_min_size = 0;
2010    xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
2011                                 xattrbuf, &xattrbuf_min_size);
2012
2013    /*
2014     * See what xattr are available.
2015     */
2016    switch (xattr_list_len) {
2017    case -1: {
2018       berrno be;
2019
2020       switch (errno) {
2021       case EOPNOTSUPP:
2022          /*
2023           * If the filesystem reports it doesn't support XATTRs we clear
2024           * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
2025           * on all other files on the same filesystem. The
2026           * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
2027           * change from one filesystem to an other.
2028           */
2029          jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
2030          retval = bxattr_exit_ok;
2031          goto bail_out;
2032       default:
2033          Mmsg2(jcr->errmsg,
2034                _("getproplist error on file \"%s\": ERR=%s\n"),
2035                jcr->last_fname, be.bstrerror());
2036          Dmsg2(100, "getproplist error file=%s ERR=%s\n",
2037                jcr->last_fname, be.bstrerror());
2038          goto bail_out;
2039       }
2040       break;
2041    }
2042    case 0:
2043       if (xattrbuf_min_size) {
2044          /*
2045           * The buffer isn't big enough to hold the xattr data, we now have
2046           * a minimum buffersize so we resize the buffer and try again.
2047           */
2048          xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
2049          xattrbuf_size = xattrbuf_min_size + 1;
2050          xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
2051                                    xattrbuf, &xattrbuf_min_size);
2052          switch (xattr_list_len) {
2053          case -1: {
2054             berrno be;
2055
2056             switch (errno) {
2057             default:
2058                Mmsg2(jcr->errmsg,
2059                      _("getproplist error on file \"%s\": ERR=%s\n"),
2060                      jcr->last_fname, be.bstrerror());
2061                Dmsg2(100, "getproplist error file=%s ERR=%s\n",
2062                      jcr->last_fname, be.bstrerror());
2063                goto bail_out;
2064             }
2065             break;
2066          }
2067          case 0:
2068             /*
2069              * This should never happen as we sized the buffer according to the minimumsize
2070              * returned by a previous getproplist call. If it does happen things are fishy and
2071              * we are better of forgetting this xattr as it seems its list is changing at this
2072              * exact moment so we can never make a good backup copy of it.
2073              */
2074             retval = bxattr_exit_ok;
2075             goto bail_out;
2076          default:
2077             break;
2078          }
2079       } else {
2080          /*
2081           * No xattr on file.
2082           */
2083          retval = bxattr_exit_ok;
2084          goto bail_out;
2085       }
2086       break;
2087    default:
2088       break;
2089    }
2090
2091    /*
2092     * Walk the list of extended attributes names and retrieve the data.
2093     * We already count the bytes needed for serializing the stream later on.
2094     */
2095    bp = xattrbuf;
2096    while (xattrbuf_size > 0) {
2097       /*
2098        * Call getproplist_entry to initialize name and value
2099        * pointers to entries position within buffer.
2100        */
2101       xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
2102
2103       /*
2104        * On some OSes you also get the acls in the extented attribute list.
2105        * So we check if we are already backing up acls and if we do we
2106        * don't store the extended attribute with the same info.
2107        */
2108       if (ff_pkt->flags & FO_ACL) {
2109          for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
2110             if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
2111                skip_xattr = true;
2112                break;
2113             }
2114          }
2115       }
2116
2117       /*
2118        * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
2119        */
2120       if (!skip_xattr) {
2121          for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
2122             if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
2123                skip_xattr = true;
2124                break;
2125             }
2126          }
2127       }
2128
2129       if (skip_xattr) {
2130          Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
2131          continue;
2132       }
2133
2134       /*
2135        * Each xattr valuepair starts with a magic so we can parse it easier.
2136        */
2137       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
2138       memset(current_xattr, 0, sizeof(xattr_t));
2139       current_xattr->magic = XATTR_MAGIC;
2140       expected_serialize_len += sizeof(current_xattr->magic);
2141
2142       current_xattr->name_length = strlen(xattr_name);
2143       current_xattr->name = bstrdup(xattr_name);
2144
2145       expected_serialize_len += sizeof(current_xattr->name_length) +
2146                                 current_xattr->name_length;
2147
2148       current_xattr->value_length = *xattr_value_len;
2149       current_xattr->value = (char *)malloc(current_xattr->value_length);
2150       memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
2151
2152       expected_serialize_len += sizeof(current_xattr->value_length) +
2153                                 current_xattr->value_length;
2154
2155       if (xattr_value_list == NULL) {
2156          xattr_value_list = New(alist(10, not_owned_by_alist));
2157       }
2158
2159       xattr_value_list->append(current_xattr);
2160       xattr_count++;
2161
2162       /*
2163        * Protect ourself against things getting out of hand.
2164        */
2165       if (expected_serialize_len >= MAX_XATTR_STREAM) {
2166          Mmsg2(jcr->errmsg,
2167                _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2168                jcr->last_fname, MAX_XATTR_STREAM);
2169          goto bail_out;
2170       }
2171    }
2172
2173    /*
2174     * If we found any xattr send them to the SD.
2175     */
2176    if (xattr_count > 0) {
2177       /*
2178        * Serialize the datastream.
2179        */
2180       if (serialize_xattr_stream(jcr,
2181                                  expected_serialize_len,
2182                                  xattr_value_list) < expected_serialize_len) {
2183          Mmsg1(jcr->errmsg,
2184                _("Failed to serialize extended attributes on file \"%s\"\n"),
2185                jcr->last_fname);
2186          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
2187                jcr->last_fname);
2188          goto bail_out;
2189       }
2190
2191       /*
2192        * Send the datastream to the SD.
2193        */
2194       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
2195    } else {
2196       retval = bxattr_exit_ok;
2197    }
2198
2199 bail_out:
2200    if (xattr_value_list != NULL) {
2201       xattr_drop_internal_table(xattr_value_list);
2202    }
2203    free_pool_memory(xattrbuf);
2204
2205    return retval;
2206 }
2207
2208 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr,
2209                                                   int stream,
2210                                                   char *content,
2211                                                   uint32_t content_length)
2212 {
2213    char *bp, *xattrbuf = NULL;
2214    int32_t xattrbuf_size, cnt;
2215    xattr_t *current_xattr;
2216    alist *xattr_value_list;
2217    bxattr_exit_code retval = bxattr_exit_error;
2218
2219    xattr_value_list = New(alist(10, not_owned_by_alist));
2220
2221    if (unserialize_xattr_stream(jcr,
2222                                 content,
2223                                 content_length,
2224                                 xattr_value_list) != bxattr_exit_ok) {
2225       goto bail_out;
2226    }
2227
2228    /*
2229     * See how big the propertylist must be.
2230     */
2231    xattrbuf_size = 0;
2232    foreach_alist(current_xattr, xattr_value_list) {
2233       xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
2234    }
2235
2236    xattrbuf = (char *)malloc(xattrbuf_size);
2237
2238    /*
2239     * Add all value pairs to the proplist.
2240     */
2241    cnt = 0;
2242    bp = xattrbuf;
2243    foreach_alist(current_xattr, xattr_value_list) {
2244       cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
2245                                current_xattr->value, &bp);
2246    }
2247
2248    /*
2249     * Sanity check.
2250     */
2251    if (cnt != xattrbuf_size) {
2252       Mmsg1(jcr->errmsg,
2253             _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
2254             jcr->last_fname);
2255       Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
2256             jcr->last_fname);
2257       goto bail_out;
2258    }
2259
2260    /*
2261     * Restore the list of extended attributes on the file.
2262     */
2263    cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
2264    switch (cnt) {
2265    case -1: {
2266       berrno be;
2267
2268       switch (errno) {
2269       case EOPNOTSUPP:
2270          /*
2271           * If the filesystem reports it doesn't support XATTRs we clear
2272           * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
2273           * on all other files on the same filesystem. The
2274           * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
2275           * change from one filesystem to an other.
2276           */
2277          jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
2278          retval = bxattr_exit_ok;
2279          goto bail_out;
2280       default:
2281          Mmsg2(jcr->errmsg,
2282                _("setproplist error on file \"%s\": ERR=%s\n"),
2283                jcr->last_fname, be.bstrerror());
2284          Dmsg2(100, "setproplist error file=%s ERR=%s\n",
2285                jcr->last_fname, be.bstrerror());
2286          goto bail_out;
2287       }
2288       break;
2289    }
2290    default:
2291       break;
2292    }
2293
2294    retval = bxattr_exit_ok;
2295
2296 bail_out:
2297    if (xattrbuf) {
2298       free(xattrbuf);
2299    }
2300    xattr_drop_internal_table(xattr_value_list);
2301
2302    return retval;
2303 }
2304
2305 /*
2306  * Function pointers to the build and parse function to use for these xattrs.
2307  */
2308 static bxattr_exit_code (*os_build_xattr_streams)
2309                         (JCR *jcr, FF_PKT *ff_pkt) =
2310                         tru64_build_xattr_streams;
2311 static bxattr_exit_code (*os_parse_xattr_streams)
2312                         (JCR *jcr, int stream, char *content, uint32_t content_length) =
2313                         tru64_parse_xattr_streams;
2314
2315 #elif defined(HAVE_SUN_OS)
2316 /*
2317  * Solaris extended attributes were introduced in Solaris 9
2318  * by PSARC 1999/209
2319  *
2320  * Solaris extensible attributes were introduced in OpenSolaris
2321  * by PSARC 2007/315 Solaris extensible attributes are also
2322  * sometimes called extended system attributes.
2323  *
2324  * man fsattr(5) on Solaris gives a wealth of info. The most
2325  * important bits are:
2326  *
2327  * Attributes are logically supported as files within the  file
2328  * system.   The  file  system  is  therefore augmented with an
2329  * orthogonal name space of file attributes. Any file  (includ-
2330  * ing  attribute files) can have an arbitrarily deep attribute
2331  * tree associated with it. Attribute values  are  accessed  by
2332  * file descriptors obtained through a special attribute inter-
2333  * face.  This logical view of "attributes as files" allows the
2334  * leveraging  of  existing file system interface functionality
2335  * to support the construction, deletion, and  manipulation  of
2336  * attributes.
2337  *
2338  * The special files  "."  and  ".."  retain  their  accustomed
2339  * semantics within the attribute hierarchy.  The "." attribute
2340  * file refers to the current directory and the ".."  attribute
2341  * file  refers to the parent directory.  The unnamed directory
2342  * at the head of each attribute tree is considered the "child"
2343  * of  the  file it is associated with and the ".." file refers
2344  * to the associated file.  For  any  non-directory  file  with
2345  * attributes,  the  ".." entry in the unnamed directory refers
2346  * to a file that is not a directory.
2347  *
2348  * Conceptually, the attribute model is fully general. Extended
2349  * attributes  can  be  any  type of file (doors, links, direc-
2350  * tories, and so forth) and can even have their own attributes
2351  * (fully  recursive).   As a result, the attributes associated
2352  * with a file could be an arbitrarily deep directory hierarchy
2353  * where each attribute could have an equally complex attribute
2354  * tree associated with it.  Not all implementations  are  able
2355  * to,  or  want to, support the full model. Implementation are
2356  * therefore permitted to reject operations that are  not  sup-
2357  * ported.   For  example,  the implementation for the UFS file
2358  * system allows only regular files as attributes (for example,
2359  * no sub-directories) and rejects attempts to place attributes
2360  * on attributes.
2361  *
2362  * The following list details the operations that are  rejected
2363  * in the current implementation:
2364  *
2365  * link                     Any attempt to create links between
2366  *                          attribute  and  non-attribute space
2367  *                          is rejected  to  prevent  security-
2368  *                          related   or   otherwise  sensitive
2369  *                          attributes from being exposed,  and
2370  *                          therefore  manipulable,  as regular
2371  *                          files.
2372  *
2373  * rename                   Any  attempt  to   rename   between
2374  *                          attribute  and  non-attribute space
2375  *                          is rejected to prevent  an  already
2376  *                          linked  file from being renamed and
2377  *                          thereby circumventing the link res-
2378  *                          triction above.
2379  *
2380  * mkdir, symlink, mknod    Any  attempt  to  create  a   "non-
2381  *                          regular" file in attribute space is
2382  *                          rejected to reduce the  functional-
2383  *                          ity,  and  therefore  exposure  and
2384  *                          risk, of  the  initial  implementa-
2385  *                          tion.
2386  *
2387  * The entire available name space has been allocated to  "gen-
2388  * eral use" to bring the implementation in line with the NFSv4
2389  * draft standard [NFSv4]. That standard defines "named  attri-
2390  * butes"  (equivalent  to Solaris Extended Attributes) with no
2391  * naming restrictions.  All Sun  applications  making  use  of
2392  * opaque extended attributes will use the prefix "SUNW".
2393  *
2394  */
2395 #ifdef HAVE_SYS_ATTR_H
2396 #include <sys/attr.h>
2397 #endif
2398
2399 #ifdef HAVE_ATTR_H
2400 #include <attr.h>
2401 #endif
2402
2403 #ifdef HAVE_SYS_NVPAIR_H
2404 #include <sys/nvpair.h>
2405 #endif
2406
2407 #ifdef HAVE_SYS_ACL_H
2408 #include <sys/acl.h>
2409 #endif
2410
2411 #if !defined(HAVE_OPENAT) || \
2412     !defined(HAVE_UNLINKAT) || \
2413     !defined(HAVE_FCHOWNAT) || \
2414     !defined(HAVE_FUTIMESAT)
2415 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2416 #endif
2417
2418 /*
2419  * Define the supported XATTR streams for this OS
2420  */
2421 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2422 static int os_default_xattr_streams[2] = {
2423    STREAM_XATTR_SOLARIS,
2424    STREAM_XATTR_SOLARIS_SYS
2425 };
2426 #else
2427 static int os_default_xattr_streams[1] = {
2428    STREAM_XATTR_SOLARIS
2429 };
2430 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2431
2432 /*
2433  * This code creates a temporary cache with entries for each xattr which has
2434  * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2435  */
2436 static inline xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2437 {
2438    xattr_link_cache_entry_t *ptr;
2439
2440    foreach_alist(ptr, jcr->xattr_data->u.build->link_cache) {
2441       if (ptr && ptr->inum == inum) {
2442          return ptr;
2443       }
2444    }
2445    return NULL;
2446 }
2447
2448 static inline void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2449 {
2450    xattr_link_cache_entry_t *ptr;
2451
2452    ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2453    memset(ptr, 0, sizeof(xattr_link_cache_entry_t));
2454    ptr->inum = inum;
2455    ptr->target = bstrdup(target);
2456
2457    if (!jcr->xattr_data->u.build->link_cache) {
2458       jcr->xattr_data->u.build->link_cache = New(alist(10, not_owned_by_alist));
2459    }
2460    jcr->xattr_data->u.build->link_cache->append(ptr);
2461 }
2462
2463 static inline void drop_xattr_link_cache(JCR *jcr)
2464 {
2465    xattr_link_cache_entry_t *ptr;
2466
2467    /*
2468     * Walk the list of xattr link cache entries and free allocated memory on traversing.
2469     */
2470    foreach_alist(ptr, jcr->xattr_data->u.build->link_cache) {
2471       free(ptr->target);
2472       free(ptr);
2473    }
2474
2475    delete jcr->xattr_data->u.build->link_cache;
2476    jcr->xattr_data->u.build->link_cache = NULL;
2477 }
2478
2479 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2480 /*
2481  * This function returns true if a non default extended system attribute
2482  * list is associated with fd and returns false when an error has occured
2483  * or when only extended system attributes other than archive,
2484  * av_modified or crtime are set.
2485  *
2486  * The function returns true for the following cases:
2487  *
2488  * - any extended system attribute other than the default attributes
2489  *   ('archive', 'av_modified' and 'crtime') is set
2490  * - nvlist has NULL name string
2491  * - nvpair has data type of 'nvlist'
2492  * - default data type.
2493  */
2494 static bool solaris_has_non_transient_extensible_attributes(int fd)
2495 {
2496    boolean_t value;
2497    data_type_t type;
2498    nvlist_t *response;
2499    nvpair_t *pair;
2500    f_attr_t fattr;
2501    char *name;
2502    bool retval = false;
2503
2504    if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2505       return false;
2506    }
2507
2508    pair = NULL;
2509    while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2510       name = nvpair_name(pair);
2511
2512       if (name != NULL) {
2513          fattr = name_to_attr(name);
2514       } else {
2515          retval = true;
2516          goto bail_out;
2517       }
2518
2519       type = nvpair_type(pair);
2520       switch (type) {
2521       case DATA_TYPE_BOOLEAN_VALUE:
2522          if (nvpair_value_boolean_value(pair, &value) != 0) {
2523             continue;
2524          }
2525          if (value && fattr != F_ARCHIVE &&
2526                       fattr != F_AV_MODIFIED) {
2527             retval = true;
2528             goto bail_out;
2529          }
2530          break;
2531       case DATA_TYPE_UINT64_ARRAY:
2532          if (fattr != F_CRTIME) {
2533             retval = true;
2534             goto bail_out;
2535          }
2536          break;
2537       case DATA_TYPE_NVLIST:
2538       default:
2539          retval = true;
2540          goto bail_out;
2541       }
2542    }
2543
2544 bail_out:
2545    if (response != NULL) {
2546       nvlist_free(response);
2547    }
2548    return retval;
2549 }
2550 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2551
2552 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2553 /*
2554  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2555  * There is no need to store those acls as we already store the stat bits too.
2556  */
2557 static bool acl_is_trivial(int count, aclent_t *entries)
2558 {
2559    int n;
2560    aclent_t *ace;
2561
2562    for (n = 0; n < count; n++) {
2563       ace = &entries[n];
2564       if (!(ace->a_type == USER_OBJ ||
2565             ace->a_type == GROUP_OBJ ||
2566             ace->a_type == OTHER_OBJ ||
2567             ace->a_type == CLASS_OBJ))
2568         return false;
2569    }
2570    return true;
2571 }
2572 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2573
2574 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2575 {
2576    bxattr_exit_code retval = bxattr_exit_error;
2577 #ifdef HAVE_ACL
2578 #ifdef HAVE_EXTENDED_ACL
2579    int flags;
2580    acl_t *aclp = NULL;
2581
2582    /*
2583     * See if this attribute has an ACL
2584     */
2585    if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2586        pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2587       /*
2588        * See if there is a non trivial acl on the file.
2589        */
2590       if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2591            acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2592          berrno be;
2593
2594          switch (errno) {
2595          case ENOENT:
2596             retval = bxattr_exit_ok;
2597             goto bail_out;
2598          default:
2599             Mmsg3(jcr->errmsg,
2600                   _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2601                   attrname, jcr->last_fname, be.bstrerror());
2602             Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2603                   attrname, jcr->last_fname, be.bstrerror());
2604             goto bail_out;
2605          }
2606       }
2607
2608       if (aclp != NULL) {
2609 #if defined(ACL_SID_FMT)
2610          /*
2611           * New format flag added in newer Solaris versions.
2612           */
2613          flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2614 #else
2615          flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2616 #endif /* ACL_SID_FMT */
2617
2618          *acl_text = acl_totext(aclp, flags);
2619          acl_free(aclp);
2620       } else {
2621          *acl_text = NULL;
2622       }
2623    } else {
2624       *acl_text = NULL;
2625    }
2626    retval = bxattr_exit_ok;
2627 #else /* HAVE_EXTENDED_ACL */
2628    int n;
2629    aclent_t *acls = NULL;
2630
2631    /*
2632     * See if this attribute has an ACL
2633     */
2634    if (fd != -1) {
2635       n = facl(fd, GETACLCNT, 0, NULL);
2636    } else {
2637       n = acl(attrname, GETACLCNT, 0, NULL);
2638    }
2639
2640    if (n >= MIN_ACL_ENTRIES) {
2641       acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2642       if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2643           acl(attrname, GETACL, n, acls) != n) {
2644          berrno be;
2645
2646          switch (errno) {
2647          case ENOENT:
2648             free(acls);
2649             retval = bxattr_exit_ok;
2650             goto bail_out;
2651          default:
2652             Mmsg3(jcr->errmsg,
2653                   _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2654                   attrname, jcr->last_fname, be.bstrerror());
2655             Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2656                   attrname, jcr->last_fname, be.bstrerror());
2657             free(acls);
2658             goto bail_out;
2659          }
2660       }
2661
2662       /*
2663        * See if there is a non trivial acl on the file.
2664        */
2665       if (!acl_is_trivial(n, acls)) {
2666          if ((*acl_text = acltotext(acls, n)) == NULL) {
2667             berrno be;
2668
2669             Mmsg3(jcr->errmsg,
2670                   _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2671                   attrname, jcr->last_fname, be.bstrerror());
2672             Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2673                   attrname, jcr->last_fname, be.bstrerror());
2674             free(acls);
2675             goto bail_out;
2676          }
2677       } else {
2678          *acl_text = NULL;
2679       }
2680
2681      free(acls);
2682    } else {
2683       *acl_text = NULL;
2684    }
2685    retval = bxattr_exit_ok;
2686 #endif /* HAVE_EXTENDED_ACL */
2687
2688 #else /* HAVE_ACL */
2689    retval = bxattr_exit_ok;
2690 #endif /* HAVE_ACL */
2691
2692 bail_out:
2693    return retval;
2694 }
2695
2696 /*
2697  * Forward declaration for recursive function call.
2698  */
2699 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2700
2701 /*
2702  * Save an extended or extensible attribute.
2703  * This is stored as an opaque stream of bytes with the following encoding:
2704  *
2705  * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2706  *
2707  * or for a hardlinked or symlinked attribute
2708  *
2709  * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2710  *
2711  * xattr_name can be a subpath relative to the file the xattr is on.
2712  * stat_buffer is the string representation of the stat struct.
2713  * acl_string is an acl text when a non trivial acl is set on the xattr.
2714  * actual_xattr_data is the content of the xattr file.
2715  */
2716 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2717                                            const char *attrname, bool toplevel_hidden_dir, int stream)
2718 {
2719    int cnt;
2720    int attrfd = -1;
2721    struct stat st;
2722    xattr_link_cache_entry_t *xlce;
2723    char target_attrname[PATH_MAX];
2724    char link_source[PATH_MAX];
2725    char *acl_text = NULL;
2726    char attribs[MAXSTRING];
2727    char buffer[XATTR_BUFSIZ];
2728    bxattr_exit_code retval = bxattr_exit_error;
2729
2730    bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2731
2732    /*
2733     * Get the stats of the extended or extensible attribute.
2734     */
2735    if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2736       berrno be;
2737
2738       switch (errno) {
2739       case ENOENT:
2740          retval = bxattr_exit_ok;
2741          goto bail_out;
2742       default:
2743          Mmsg3(jcr->errmsg,
2744                _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2745                target_attrname, jcr->last_fname, be.bstrerror());
2746          Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2747                target_attrname, jcr->last_fname, be.bstrerror());
2748          goto bail_out;
2749       }
2750    }
2751
2752    /*
2753     * Based on the filetype perform the correct action. We support most filetypes here, more
2754     * then the actual implementation on Solaris supports so some code may never get executed
2755     * due to limitations in the implementation.
2756     */
2757    switch (st.st_mode & S_IFMT) {
2758    case S_IFIFO:
2759    case S_IFCHR:
2760    case S_IFBLK:
2761       /*
2762        * Get any acl on the xattr.
2763        */
2764       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2765          goto bail_out;
2766
2767       /*
2768        * The current implementation of xattr on Solaris doesn't support this,
2769        * but if it ever does we are prepared.
2770        * Encode the stat struct into an ASCII representation.
2771        */
2772       encode_stat(attribs, &st, sizeof(st), 0, stream);
2773       cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2774                       target_attrname, 0, attribs, 0,
2775                       (acl_text) ? acl_text : "", 0);
2776       break;
2777    case S_IFDIR:
2778       /*
2779        * Get any acl on the xattr.
2780        */
2781       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2782          goto bail_out;
2783
2784       /*
2785        * See if this is the toplevel_hidden_dir being saved.
2786        */
2787       if (toplevel_hidden_dir) {
2788          /*
2789           * Save the data for later storage when we encounter a real xattr.
2790           * We store the data in the jcr->xattr_data->u.build->content buffer
2791           * and flush that just before sending out the first real xattr.
2792           * Encode the stat struct into an ASCII representation and jump
2793           * out of the function.
2794           */
2795          encode_stat(attribs, &st, sizeof(st), 0, stream);
2796          cnt = bsnprintf(buffer, sizeof(buffer),
2797                          "%s%c%s%c%s%c",
2798                          target_attrname, 0, attribs, 0,
2799                          (acl_text) ? acl_text : "", 0);
2800          pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2801          jcr->xattr_data->u.build->content_length = cnt;
2802          goto bail_out;
2803       } else {
2804          /*
2805           * The current implementation of xattr on Solaris doesn't support this,
2806           * but if it ever does we are prepared.
2807           * Encode the stat struct into an ASCII representation.
2808           */
2809          encode_stat(attribs, &st, sizeof(st), 0, stream);
2810          cnt = bsnprintf(buffer, sizeof(buffer),
2811                          "%s%c%s%c%s%c",
2812                          target_attrname, 0, attribs, 0,
2813                          (acl_text) ? acl_text : "", 0);
2814       }
2815       break;
2816    case S_IFREG:
2817       /*
2818        * If this is a hardlinked file check the inode cache for a hit.
2819        */
2820       if (st.st_nlink > 1) {
2821          /*
2822           * See if the cache already knows this inode number.
2823           */
2824          if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2825             /*
2826              * Generate a xattr encoding with the reference to the target in there.
2827              */
2828             encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2829             cnt = bsnprintf(buffer, sizeof(buffer),
2830                             "%s%c%s%c%s%c",
2831                             target_attrname, 0, attribs, 0, xlce->target, 0);
2832             pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2833             jcr->xattr_data->u.build->content_length = cnt;
2834             retval = send_xattr_stream(jcr, stream);
2835
2836             /*
2837              * For a hard linked file we are ready now, no need to recursively
2838              * save the attributes.
2839              */
2840             goto bail_out;
2841          }
2842
2843          /*
2844           * Store this hard linked file in the cache.
2845           * Store the name relative to the top level xattr space.
2846           */
2847          add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2848       }
2849
2850       /*
2851        * Get any acl on the xattr.
2852        */
2853       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2854          goto bail_out;
2855       }
2856
2857       /*
2858        * Encode the stat struct into an ASCII representation.
2859        */
2860       encode_stat(attribs, &st, sizeof(st), 0, stream);
2861       cnt = bsnprintf(buffer, sizeof(buffer),
2862                      "%s%c%s%c%s%c",
2863                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2864
2865       /*
2866        * Open the extended or extensible attribute file.
2867        */
2868       if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2869          berrno be;
2870
2871          switch (errno) {
2872          case ENOENT:
2873             retval = bxattr_exit_ok;
2874             goto bail_out;
2875          default:
2876             Mmsg3(jcr->errmsg,
2877                   _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2878                   target_attrname, jcr->last_fname, be.bstrerror());
2879             Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2880                   target_attrname, jcr->last_fname, be.bstrerror());
2881             goto bail_out;
2882          }
2883       }
2884       break;
2885    case S_IFLNK:
2886       /*
2887        * The current implementation of xattr on Solaris doesn't support this, but if it
2888        * ever does we are prepared.
2889        * Encode the stat struct into an ASCII representation.
2890        */
2891       if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2892          berrno be;
2893
2894          switch (errno) {
2895          case ENOENT:
2896             retval = bxattr_exit_ok;
2897             goto bail_out;
2898          default:
2899             Mmsg3(jcr->errmsg,
2900                   _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2901                   target_attrname, jcr->last_fname, be.bstrerror());
2902             Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2903                   target_attrname, jcr->last_fname, be.bstrerror());
2904             goto bail_out;
2905          }
2906       }
2907
2908       /*
2909        * Generate a xattr encoding with the reference to the target in there.
2910        */
2911       encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2912       cnt = bsnprintf(buffer, sizeof(buffer),
2913                       "%s%c%s%c%s%c",
2914                       target_attrname, 0, attribs, 0, link_source, 0);
2915       pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2916       jcr->xattr_data->u.build->content_length = cnt;
2917       retval = send_xattr_stream(jcr, stream);
2918
2919       if (retval == bxattr_exit_ok) {
2920          jcr->xattr_data->u.build->nr_saved++;
2921       }
2922
2923       /*
2924        * For a soft linked file we are ready now, no need to recursively save the attributes.
2925        */
2926       goto bail_out;
2927    default:
2928       goto bail_out;
2929    }
2930
2931    /*
2932     * See if this is the first real xattr being saved.
2933     * If it is save the toplevel_hidden_dir attributes first.
2934     * This is easy as its stored already in the
2935     * jcr->xattr_data->u.build->content buffer.
2936     */
2937    if (jcr->xattr_data->u.build->nr_saved == 0) {
2938       retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2939       if (retval != bxattr_exit_ok) {
2940          goto bail_out;
2941       }
2942       jcr->xattr_data->u.build->nr_saved++;
2943    }
2944
2945    pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2946    jcr->xattr_data->u.build->content_length = cnt;
2947
2948    /*
2949     * Only dump the content of regular files.
2950     */
2951    switch (st.st_mode & S_IFMT) {
2952    case S_IFREG:
2953       if (st.st_size > 0) {
2954          /*
2955           * Protect ourself against things getting out of hand.
2956           */
2957          if (st.st_size >= MAX_XATTR_STREAM) {
2958             Mmsg2(jcr->errmsg,
2959                   _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2960                   jcr->last_fname, MAX_XATTR_STREAM);
2961             goto bail_out;
2962          }
2963
2964          while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2965             jcr->xattr_data->u.build->content =
2966             check_pool_memory_size(jcr->xattr_data->u.build->content,
2967                                    jcr->xattr_data->u.build->content_length + cnt);
2968             memcpy(jcr->xattr_data->u.build->content +
2969                    jcr->xattr_data->u.build->content_length, buffer, cnt);
2970             jcr->xattr_data->u.build->content_length += cnt;
2971          }
2972
2973          if (cnt < 0) {
2974             Mmsg2(jcr->errmsg,
2975                   _("Unable to read content of xattr %s on file \"%s\"\n"),
2976                   target_attrname, jcr->last_fname);
2977             Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2978                   target_attrname, jcr->last_fname);
2979             goto bail_out;
2980          }
2981       }
2982       break;
2983
2984    default:
2985       break;
2986    }
2987
2988    /*
2989     * We build a new xattr stream send it to the SD.
2990     */
2991    retval = send_xattr_stream(jcr, stream);
2992    if (retval != bxattr_exit_ok) {
2993        goto bail_out;
2994    }
2995    jcr->xattr_data->u.build->nr_saved++;
2996
2997    /*
2998     * Recursivly call solaris_save_extended_attributes for archiving the attributes
2999     * available on this extended attribute.
3000     */
3001    retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
3002
3003    /*
3004     * The recursive call could change our working dir so change back to the wanted workdir.
3005     */
3006    if (fchdir(fd) < 0) {
3007       berrno be;
3008
3009       switch (errno) {
3010       case ENOENT:
3011          retval = bxattr_exit_ok;
3012          goto bail_out;
3013       default:
3014          Mmsg2(jcr->errmsg,
3015                _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
3016                jcr->last_fname, be.bstrerror());
3017          Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
3018                jcr->last_fname, fd, be.bstrerror());
3019          goto bail_out;
3020       }
3021    }
3022
3023 bail_out:
3024    if (acl_text != NULL) {
3025       free(acl_text);
3026    }
3027    if (attrfd != -1) {
3028       close(attrfd);
3029    }
3030    return retval;
3031 }
3032
3033 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
3034 {
3035    const char *name;
3036    int fd, filefd = -1, attrdirfd = -1;
3037    DIR *dirp;
3038    struct dirent *dp;
3039    char current_xattr_namespace[PATH_MAX];
3040    bxattr_exit_code retval = bxattr_exit_error;
3041
3042    /*
3043     * Determine what argument to use. Use attr_parent when set
3044     * (recursive call) or jcr->last_fname for first call. Also save
3045     * the current depth of the xattr_space we are in.
3046     */
3047    if (attr_parent) {
3048       name = attr_parent;
3049       if (xattr_namespace) {
3050          bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
3051                    xattr_namespace, attr_parent);
3052       } else {
3053          bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
3054       }
3055    } else {
3056       name = jcr->last_fname;
3057       bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
3058    }
3059
3060    /*
3061     * Open the file on which to save the xattrs read-only.
3062     */
3063    if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
3064       berrno be;
3065
3066       switch (errno) {
3067       case ENOENT:
3068          retval = bxattr_exit_ok;
3069          goto bail_out;
3070       default:
3071          Mmsg2(jcr->errmsg,
3072                _("Unable to open file \"%s\": ERR=%s\n"),
3073                jcr->last_fname, be.bstrerror());
3074          Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
3075                jcr->last_fname, be.bstrerror());
3076          goto bail_out;
3077       }
3078    }
3079
3080    /*
3081     * Open the xattr naming space.
3082     */
3083    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3084       berrno be;
3085
3086       switch (errno) {
3087       case EINVAL:
3088          /*
3089           * Gentile way of the system saying this type of xattr layering is not supported.
3090           * Which is not problem we just forget about this this xattr.
3091           * But as this is not an error we return a positive return value.
3092           */
3093          retval = bxattr_exit_ok;
3094          goto bail_out;
3095       case ENOENT:
3096          retval = bxattr_exit_ok;
3097          goto bail_out;
3098       default:
3099          Mmsg3(jcr->errmsg,
3100                _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
3101                name, jcr->last_fname, be.bstrerror());
3102          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
3103                name, jcr->last_fname, be.bstrerror());
3104          goto bail_out;
3105       }
3106    }
3107
3108   /*
3109    * We need to change into the attribute directory to determine if each of the
3110    * attributes should be saved.
3111    */
3112    if (fchdir(attrdirfd) < 0) {
3113       berrno be;
3114
3115       Mmsg2(jcr->errmsg,
3116             _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3117             jcr->last_fname, be.bstrerror());
3118       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
3119             jcr->last_fname, attrdirfd, be.bstrerror());
3120       goto bail_out;
3121    }
3122
3123    /*
3124     * Save the data of the toplevel xattr hidden_dir. We save this one before anything
3125     * else because the readdir returns "." entry after the extensible attr entry.
3126     * And as we want this entry before anything else we better just save its data.
3127     */
3128    if (!attr_parent)
3129       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
3130                          true, STREAM_XATTR_SOLARIS);
3131
3132    if ((fd = dup(attrdirfd)) == -1 ||
3133        (dirp = fdopendir(fd)) == (DIR *)NULL) {
3134       berrno be;
3135
3136       Mmsg2(jcr->errmsg,
3137             _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
3138             jcr->last_fname, be.bstrerror());
3139       Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
3140             jcr->last_fname, fd, be.bstrerror());
3141
3142       goto bail_out;
3143    }
3144
3145    /*
3146     * Walk the namespace.
3147     */
3148    while ((dp = readdir(dirp)) != NULL) {
3149       /*
3150        * Skip only the toplevel . dir.
3151        */
3152       if (!attr_parent && bstrcmp(dp->d_name, "."))
3153          continue;
3154
3155       /*
3156        * Skip all .. directories
3157        */
3158       if (bstrcmp(dp->d_name, ".."))
3159          continue;
3160
3161       Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
3162          current_xattr_namespace, dp->d_name, jcr->last_fname);
3163
3164 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3165       /*
3166        * We are not interested in read-only extensible attributes.
3167        */
3168       if (bstrcmp(dp->d_name, VIEW_READONLY)) {
3169          Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
3170             current_xattr_namespace, dp->d_name, jcr->last_fname);
3171
3172          continue;
3173       }
3174
3175       /*
3176        * We are only interested in read-write extensible attributes
3177        * when they contain non-transient values.
3178        */
3179       if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
3180          /*
3181           * Determine if there are non-transient system attributes at the toplevel.
3182           * We need to provide a fd to the open file.
3183           */
3184          if (!solaris_has_non_transient_extensible_attributes(filefd)) {
3185             Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
3186                current_xattr_namespace, dp->d_name, jcr->last_fname);
3187             continue;
3188          }
3189
3190          /*
3191           * Save the xattr.
3192           */
3193          solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3194                             false, STREAM_XATTR_SOLARIS_SYS);
3195          continue;
3196       }
3197 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
3198
3199       /*
3200        * Save the xattr.
3201        */
3202       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3203                          false, STREAM_XATTR_SOLARIS);
3204    }
3205
3206    closedir(dirp);
3207    retval = bxattr_exit_ok;
3208
3209 bail_out:
3210    if (attrdirfd != -1)
3211       close(attrdirfd);
3212    if (filefd != -1)
3213       close(filefd);
3214    return retval;
3215 }
3216
3217 #ifdef HAVE_ACL
3218 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr,
3219                                                   int fd,
3220                                                   const char *attrname,
3221                                                   char *acl_text)
3222 {
3223 #ifdef HAVE_EXTENDED_ACL
3224    int error;
3225    acl_t *aclp = NULL;
3226
3227    if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
3228       Mmsg1(jcr->errmsg,
3229             _("Unable to convert acl from text on file \"%s\"\n"),
3230             jcr->last_fname);
3231       return bxattr_exit_error;
3232    }
3233
3234    if ((fd != -1 && facl_set(fd, aclp) != 0) ||
3235         acl_set(attrname, aclp) != 0) {
3236       berrno be;
3237
3238       Mmsg3(jcr->errmsg,
3239             _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3240             attrname, jcr->last_fname, be.bstrerror());
3241       Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3242             attrname, jcr->last_fname, be.bstrerror());
3243       return bxattr_exit_error;
3244    }
3245
3246    if (aclp) {
3247       acl_free(aclp);
3248    }
3249    return bxattr_exit_ok;
3250
3251 #else /* HAVE_EXTENDED_ACL */
3252    int n;
3253    aclent_t *acls = NULL;
3254
3255    acls = aclfromtext(acl_text, &n);
3256    if (!acls) {
3257       if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
3258            acl(attrname, SETACL, n, acls) != 0) {
3259          berrno be;
3260
3261          Mmsg3(jcr->errmsg,
3262                _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3263                attrname, jcr->last_fname, be.bstrerror());
3264          Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3265                attrname, jcr->last_fname, be.bstrerror());
3266          return bxattr_exit_error;
3267       }
3268    }
3269
3270    if (acls) {
3271       free(acls);
3272    }
3273    return bxattr_exit_ok;
3274
3275 #endif /* HAVE_EXTENDED_ACL */
3276
3277 }
3278 #endif /* HAVE_ACL */
3279
3280 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr,
3281                                                bool is_extensible,
3282                                                char *content,
3283                                                uint32_t content_length)
3284
3285 {
3286    int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
3287    int used_bytes, cnt;
3288    char *bp, *target_attrname, *attribs;
3289    char *linked_target = NULL;
3290    char *acl_text = NULL;
3291    char *data = NULL;
3292    int32_t inum;
3293    struct stat st;
3294    struct timeval times[2];
3295    bxattr_exit_code retval = bxattr_exit_error;
3296
3297    /*
3298     * Parse the xattr stream. First the part that is the same for all xattrs.
3299     */
3300    used_bytes = 0;
3301
3302    /*
3303     * The name of the target xattr has a leading / we are not interested
3304     * in that so skip it when decoding the string. We always start a the /
3305     * of the xattr space anyway.
3306     */
3307    target_attrname = content + 1;
3308    if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
3309        (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3310       goto parse_error;
3311    }
3312    attribs = ++bp;
3313
3314    /*
3315     * Open the file on which to restore the xattrs read-only.
3316     */
3317    if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
3318       berrno be;
3319
3320       Mmsg2(jcr->errmsg,
3321             _("Unable to open file \"%s\": ERR=%s\n"),
3322             jcr->last_fname, be.bstrerror());
3323       Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
3324             jcr->last_fname, be.bstrerror());
3325       goto bail_out;
3326    }
3327
3328    /*
3329     * Open the xattr naming space and make it the current working dir.
3330     */
3331    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3332       berrno be;
3333
3334       Mmsg2(jcr->errmsg,
3335             _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
3336             jcr->last_fname, be.bstrerror());
3337       Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
3338             jcr->last_fname, be.bstrerror());
3339       goto bail_out;
3340    }
3341
3342    if (fchdir(attrdirfd) < 0) {
3343       berrno be;
3344
3345       Mmsg2(jcr->errmsg,
3346             _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3347             jcr->last_fname, be.bstrerror());
3348       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
3349             jcr->last_fname, attrdirfd, be.bstrerror());
3350       goto bail_out;
3351    }
3352
3353    /*
3354     * Try to open the correct xattr subdir based on the target_attrname given.
3355     * e.g. check if its a subdir attrname. Each / in the string makes us go
3356     * one level deeper.
3357     */
3358    while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
3359       *bp = '\0';
3360
3361       if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
3362          berrno be;
3363
3364          Mmsg3(jcr->errmsg,
3365                _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3366                target_attrname, jcr->last_fname, be.bstrerror());
3367          Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3368                target_attrname, jcr->last_fname, be.bstrerror());
3369          goto bail_out;
3370       }
3371
3372       close(filefd);
3373       filefd = fd;
3374
3375       /*
3376        * Open the xattr naming space.
3377        */
3378       if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3379          berrno be;
3380
3381          Mmsg3(jcr->errmsg,
3382                _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
3383                target_attrname, jcr->last_fname, be.bstrerror());
3384          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
3385                target_attrname, jcr->last_fname, be.bstrerror());
3386          goto bail_out;
3387       }
3388
3389       close(attrdirfd);
3390       attrdirfd = fd;
3391
3392       /*
3393        * Make the xattr space our current workingdir.
3394        */
3395       if (fchdir(attrdirfd) < 0) {
3396          berrno be;
3397
3398          Mmsg3(jcr->errmsg,
3399                _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
3400                target_attrname, jcr->last_fname, be.bstrerror());
3401          Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
3402                target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
3403          goto bail_out;
3404       }
3405
3406       target_attrname = ++bp;
3407    }
3408
3409    /*
3410     * Decode the attributes from the stream.
3411     */
3412    decode_stat(attribs, &st, sizeof(st), &inum);
3413
3414    /*
3415     * Decode the next field (acl_text).
3416     */
3417    if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
3418        (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3419       goto parse_error;
3420    }
3421    acl_text = ++bp;
3422
3423    /*
3424     * Based on the filetype perform the correct action. We support most filetypes here, more
3425     * then the actual implementation on Solaris supports so some code may never get executed
3426     * due to limitations in the implementation.
3427     */
3428    switch (st.st_mode & S_IFMT) {
3429    case S_IFIFO:
3430       /*
3431        * The current implementation of xattr on Solaris doesn't support this,
3432        * but if it ever does we are prepared.
3433        */
3434       unlinkat(attrdirfd, target_attrname, 0);
3435       if (mkfifo(target_attrname, st.st_mode) < 0) {
3436          berrno be;
3437
3438          Mmsg3(jcr->errmsg,
3439                _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3440                target_attrname, jcr->last_fname, be.bstrerror());
3441          Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
3442                target_attrname,  jcr->last_fname, be.bstrerror());
3443          goto bail_out;
3444       }
3445       break;
3446    case S_IFCHR:
3447    case S_IFBLK:
3448       /*
3449        * The current implementation of xattr on Solaris doesn't support this,
3450        * but if it ever does we are prepared.
3451        */
3452       unlinkat(attrdirfd, target_attrname, 0);
3453       if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3454          berrno be;
3455
3456          Mmsg3(jcr->errmsg,
3457                _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3458                target_attrname, jcr->last_fname, be.bstrerror());
3459          Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3460                target_attrname,  jcr->last_fname, be.bstrerror());
3461          goto bail_out;
3462       }
3463       break;
3464    case S_IFDIR:
3465       /*
3466        * If its not the hidden_dir create the entry.
3467        * The current implementation of xattr on Solaris doesn't support this,
3468        * but if it ever does we are prepared.
3469        */
3470       if (!bstrcmp(target_attrname, ".")) {
3471          unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3472          if (mkdir(target_attrname, st.st_mode) < 0) {
3473             berrno be;
3474
3475             Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3476                target_attrname, jcr->last_fname, be.bstrerror());
3477             Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3478                target_attrname,  jcr->last_fname, be.bstrerror());
3479             goto bail_out;
3480          }
3481       }
3482       break;
3483    case S_IFREG:
3484       /*
3485        * See if this is a hard linked file. e.g. inum != 0
3486        */
3487       if (inum != 0) {
3488          linked_target = bp;
3489
3490          unlinkat(attrdirfd, target_attrname, 0);
3491          if (link(linked_target, target_attrname) < 0) {
3492             berrno be;
3493
3494             Mmsg4(jcr->errmsg,
3495                   _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3496                   target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3497             Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3498                   target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3499             goto bail_out;
3500          }
3501
3502          /*
3503           * Successfully restored xattr.
3504           */
3505          retval = bxattr_exit_ok;
3506          goto bail_out;
3507       } else {
3508          if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3509              (used_bytes = (bp - content)) >= (int32_t)content_length) {
3510             goto parse_error;
3511          }
3512
3513          if (used_bytes < (int32_t)(content_length - 1))
3514             data = ++bp;
3515
3516          /*
3517           * Restore the actual xattr.
3518           */
3519          if (!is_extensible) {
3520             unlinkat(attrdirfd, target_attrname, 0);
3521          }
3522
3523          if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3524             berrno be;
3525
3526             Mmsg3(jcr->errmsg,
3527                   _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3528                   target_attrname, jcr->last_fname, be.bstrerror());
3529             Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3530                   target_attrname, jcr->last_fname, be.bstrerror());
3531             goto bail_out;
3532          }
3533       }
3534
3535       /*
3536        * Restore the actual data.
3537        */
3538       if (st.st_size > 0) {
3539          used_bytes = (data - content);
3540          cnt = content_length - used_bytes;
3541
3542          /*
3543           * Do a sanity check, the st.st_size should be the same as the number of bytes
3544           * we have available as data of the stream.
3545           */
3546          if (cnt != st.st_size) {
3547             Mmsg2(jcr->errmsg,
3548                   _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3549                   target_attrname, jcr->last_fname);
3550             Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3551                   target_attrname, jcr->last_fname);
3552             goto bail_out;
3553          }
3554
3555          while (cnt > 0) {
3556             cnt = write(attrfd, data, cnt);
3557             if (cnt < 0) {
3558                berrno be;
3559
3560                Mmsg3(jcr->errmsg,
3561                      _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3562                      target_attrname, jcr->last_fname, be.bstrerror());
3563                Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3564                      target_attrname, jcr->last_fname, be.bstrerror());
3565                goto bail_out;
3566             }
3567
3568             used_bytes += cnt;
3569             data += cnt;
3570             cnt = content_length - used_bytes;
3571          }
3572       }
3573       break;
3574    case S_IFLNK:
3575       /*
3576        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3577        */
3578       linked_target = bp;
3579
3580       if (symlink(linked_target, target_attrname) < 0) {
3581          berrno be;
3582
3583          Mmsg4(jcr->errmsg,
3584                _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3585                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3586          Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3587                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3588          goto bail_out;
3589       }
3590
3591       /*
3592        * Successfully restored xattr.
3593        */
3594       retval = bxattr_exit_ok;
3595       goto bail_out;
3596    default:
3597       goto bail_out;
3598    }
3599
3600    /*
3601     * Restore owner and acl for non extensible attributes.
3602     */
3603    if (!is_extensible) {
3604       if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3605          berrno be;
3606
3607          switch (errno) {
3608          case EINVAL:
3609             /*
3610              * Gentile way of the system saying this type of xattr layering is not supported.
3611              * But as this is not an error we return a positive return value.
3612              */
3613             retval = bxattr_exit_ok;
3614             break;
3615          case ENOENT:
3616             retval = bxattr_exit_ok;
3617             break;
3618          default:
3619             Mmsg3(jcr->errmsg,
3620                   _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3621                   target_attrname, jcr->last_fname, be.bstrerror());
3622             Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3623                   target_attrname, jcr->last_fname, be.bstrerror());
3624          }
3625          goto bail_out;
3626       }
3627    }
3628
3629 #ifdef HAVE_ACL
3630    if (acl_text && *acl_text)
3631       if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3632          goto bail_out;
3633 #endif /* HAVE_ACL */
3634
3635    /*
3636     * For a non extensible attribute restore access and modification time on the xattr.
3637     */
3638    if (!is_extensible) {
3639       times[0].tv_sec = st.st_atime;
3640       times[0].tv_usec = 0;
3641       times[1].tv_sec = st.st_mtime;
3642       times[1].tv_usec = 0;
3643
3644       if (futimesat(attrdirfd, target_attrname, times) < 0) {
3645          berrno be;
3646
3647          Mmsg3(jcr->errmsg,
3648                _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3649                target_attrname, jcr->last_fname, be.bstrerror());
3650          Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3651                target_attrname, jcr->last_fname, be.bstrerror());
3652          goto bail_out;
3653       }
3654    }
3655
3656    /*
3657     * Successfully restored xattr.
3658     */
3659    retval = bxattr_exit_ok;
3660    goto bail_out;
3661
3662 parse_error:
3663    Mmsg1(jcr->errmsg,
3664          _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3665          jcr->last_fname);
3666    Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3667          jcr->last_fname);
3668
3669 bail_out:
3670    if (attrfd != -1) {
3671       close(attrfd);
3672    }
3673    if (attrdirfd != -1) {
3674       close(attrdirfd);
3675    }
3676    if (filefd != -1) {
3677       close(filefd);
3678    }
3679    return retval;
3680 }
3681
3682 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3683 {
3684    char cwd[PATH_MAX];
3685    bxattr_exit_code retval = bxattr_exit_ok;
3686
3687    /*
3688     * First see if extended attributes or extensible attributes are present.
3689     * If not just pretend things went ok.
3690     */
3691    if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3692       jcr->xattr_data->u.build->nr_saved = 0;
3693
3694       /*
3695        * As we change the cwd in the save function save the current cwd
3696        * for restore after return from the solaris_save_xattrs function.
3697        */
3698       getcwd(cwd, sizeof(cwd));
3699       retval = solaris_save_xattrs(jcr, NULL, NULL);
3700       chdir(cwd);
3701       if (jcr->xattr_data->u.build->link_cache) {
3702          drop_xattr_link_cache(jcr);
3703       }
3704    }
3705    return retval;
3706 }
3707
3708 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr,
3709                                                     int stream,
3710                                                     char *content,
3711                                                     uint32_t content_length)
3712 {
3713    char cwd[PATH_MAX];
3714    bool is_extensible = false;
3715    bxattr_exit_code retval = bxattr_exit_error;
3716
3717    /*
3718     * First make sure we can restore xattr on the filesystem.
3719     */
3720    switch (stream) {
3721 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3722    case STREAM_XATTR_SOLARIS_SYS:
3723       if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3724          Mmsg1(jcr->errmsg,
3725          _("Failed to restore extensible attributes on file \"%s\"\n"),
3726          jcr->last_fname);
3727          Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3728             jcr->last_fname);
3729          goto bail_out;
3730       }
3731
3732       is_extensible = true;
3733       break;
3734 #endif
3735    case STREAM_XATTR_SOLARIS:
3736       if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3737          Mmsg1(jcr->errmsg,
3738                _("Failed to restore extended attributes on file \"%s\"\n"),
3739                jcr->last_fname);
3740          Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3741             jcr->last_fname);
3742          goto bail_out;
3743       }
3744       break;
3745    default:
3746       goto bail_out;
3747    }
3748
3749    /*
3750     * As we change the cwd in the restore function save the current cwd
3751     * for restore after return from the solaris_restore_xattrs function.
3752     */
3753    getcwd(cwd, sizeof(cwd));
3754    retval = solaris_restore_xattrs(jcr, is_extensible, content, content_length);
3755    chdir(cwd);
3756
3757 bail_out:
3758    return retval;
3759 }
3760
3761
3762 /*
3763  * Function pointers to the build and parse function to use for these xattrs.
3764  */
3765 static bxattr_exit_code (*os_build_xattr_streams)
3766                         (JCR *jcr, FF_PKT *ff_pkt) =
3767                         solaris_build_xattr_streams;
3768 static bxattr_exit_code (*os_parse_xattr_streams)
3769                         (JCR *jcr, int stream, char *content, uint32_t content_length) =
3770                         solaris_parse_xattr_streams;
3771
3772 #endif /* defined(HAVE_SUN_OS) */
3773
3774 /*
3775  * Entry points when compiled with support for XATTRs on a supported platform.
3776  */
3777 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3778 {
3779    /*
3780     * See if we are changing from one device to an other.
3781     * We save the current device we are scanning and compare
3782     * it with the current st_dev in the last stat performed on
3783     * the file we are currently storing.
3784     */
3785    if (jcr->xattr_data->current_dev != ff_pkt->statp.st_dev) {
3786       /*
3787        * Reset the acl save flags.
3788        */
3789       jcr->xattr_data->flags = 0;
3790       jcr->xattr_data->flags |= BXATTR_FLAG_SAVE_NATIVE;
3791
3792       /*
3793        * Save that we started scanning a new filesystem.
3794        */
3795       jcr->xattr_data->current_dev = ff_pkt->statp.st_dev;
3796    }
3797
3798    if ((jcr->xattr_data->flags & BXATTR_FLAG_SAVE_NATIVE) && os_parse_xattr_streams) {
3799       return os_build_xattr_streams(jcr, ff_pkt);
3800    } else {
3801       return bxattr_exit_ok;
3802    }
3803 }
3804
3805 bxattr_exit_code parse_xattr_streams(JCR *jcr,
3806                                      int stream,
3807                                      char *content,
3808                                      uint32_t content_length)
3809 {
3810    int ret;
3811    struct stat st;
3812    unsigned int cnt;
3813    bxattr_exit_code retval = bxattr_exit_error;
3814
3815    /*
3816     * See if we are changing from one device to an other.
3817     * We save the current device we are restoring to and compare
3818     * it with the current st_dev in the last stat performed on
3819     * the file we are currently restoring.
3820     */
3821    ret = lstat(jcr->last_fname, &st);
3822    switch (ret) {
3823    case -1: {
3824       berrno be;
3825
3826       switch (errno) {
3827       case ENOENT:
3828          retval = bxattr_exit_ok;
3829          goto bail_out;
3830       default:
3831          Mmsg2(jcr->errmsg,
3832                _("Unable to stat file \"%s\": ERR=%s\n"),
3833                jcr->last_fname, be.bstrerror());
3834          Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
3835                jcr->last_fname, be.bstrerror());
3836          goto bail_out;
3837       }
3838       break;
3839    }
3840    case 0:
3841       break;
3842    }
3843    if (jcr->xattr_data->current_dev != st.st_dev) {
3844       /*
3845        * Reset the acl save flags.
3846        */
3847       jcr->xattr_data->flags = 0;
3848       jcr->xattr_data->flags |= BXATTR_FLAG_RESTORE_NATIVE;
3849
3850       /*
3851        * Save that we started restoring to a new filesystem.
3852        */
3853       jcr->xattr_data->current_dev = st.st_dev;
3854    }
3855
3856    /*
3857     * See if we are still restoring native xattr to this filesystem.
3858     */
3859    if ((jcr->xattr_data->flags & BXATTR_FLAG_RESTORE_NATIVE) && os_parse_xattr_streams) {
3860       /*
3861        * See if we can parse this stream, and ifso give it a try.
3862        */
3863       for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3864          if (os_default_xattr_streams[cnt] == stream) {
3865             retval = os_parse_xattr_streams(jcr, stream, content, content_length);
3866             goto bail_out;
3867          }
3868       }
3869    } else {
3870       /*
3871        * Increment error count but don't log an error again for the same filesystem.
3872        */
3873       jcr->xattr_data->u.parse->nr_errors++;
3874       retval = bxattr_exit_ok;
3875       goto bail_out;
3876    }
3877
3878    /*
3879     * Issue a warning and discard the message. But pretend the restore was ok.
3880     */
3881    Jmsg2(jcr, M_WARNING, 0,
3882          _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3883          jcr->last_fname, stream);
3884
3885 bail_out:
3886    return retval;
3887 }
3888 #endif