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