]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/xattr.c
Change all sm_checks into Dsm_check for performance reasons
[bacula/bacula] / bacula / src / filed / xattr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2008-2010 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        * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
1307        * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
1308        */
1309       if (extattr_namespace_to_string(attrnamespace, &current_attrnamespace) != 0) {
1310          Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
1311                attrnamespace, jcr->last_fname);
1312          Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1313                attrnamespace, jcr->last_fname);
1314          goto bail_out;
1315       }
1316
1317       /*
1318        * First get the length of the available list with extended attributes.
1319        * If we get EPERM on system namespace, don't return error.
1320        * This is expected for normal users trying to archive the system
1321        * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1322        * they've decided to return EOPNOTSUPP instead.
1323        */
1324       xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1325       switch (xattr_list_len) {
1326       case -1:
1327          switch (errno) {
1328          case ENOENT:
1329             retval = bxattr_exit_ok;
1330             goto bail_out;
1331 #if defined(EOPNOTSUPP)
1332          case EOPNOTSUPP:
1333 #endif
1334          case EPERM:
1335             if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1336                actuallyfree(current_attrnamespace);
1337                current_attrnamespace = NULL;
1338                continue;
1339             }
1340             /*
1341              * FALLTHROUGH
1342              */
1343          default:
1344             Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1345                   jcr->last_fname, be.bstrerror());
1346             Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1347                   jcr->last_fname, be.bstrerror());
1348             goto bail_out;
1349          }
1350          break;
1351       case 0:
1352          continue;
1353       default:
1354          break;
1355       }
1356
1357       /*
1358        * Allocate room for the extented attribute list.
1359        */
1360       xattr_list = (char *)malloc(xattr_list_len + 1);
1361       memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
1362
1363       /*
1364        * Get the actual list of extended attributes names for a file.
1365        */
1366       xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
1367       switch (xattr_list_len) {
1368       case -1:
1369          switch (errno) {
1370          case ENOENT:
1371             retval = bxattr_exit_ok;
1372             goto bail_out;
1373          default:
1374             Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1375                   jcr->last_fname, be.bstrerror());
1376             Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1377                   jcr->last_fname, be.bstrerror());
1378             goto bail_out;
1379          }
1380          break;
1381       default:
1382          break;
1383       }
1384       xattr_list[xattr_list_len] = '\0';
1385
1386       /*
1387        * Walk the list of extended attributes names and retrieve the data.
1388        * We already count the bytes needed for serializing the stream later on.
1389        */
1390       for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1391          skip_xattr = false;
1392
1393          /*
1394           * Print the current name into the buffer as its not null terminated we need to
1395           * use the length encoded in the string for copying only the needed bytes.
1396           */
1397          cnt = xattr_list[index];
1398          if (cnt > ((int)sizeof(current_attrname) - 1)) {
1399             cnt = ((int)sizeof(current_attrname) - 1);
1400          }
1401          strncpy(current_attrname, xattr_list + (index + 1), cnt);
1402          current_attrname[cnt] = '\0';
1403
1404          /*
1405           * First make a xattr tuple of the current namespace and the name of the xattr.
1406           * e.g. something like user.<attrname> or system.<attrname>
1407           */
1408          bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
1409
1410          /*
1411           * On some OSes you also get the acls in the extented attribute list.
1412           * So we check if we are already backing up acls and if we do we
1413           * don't store the extended attribute with the same info.
1414           */
1415          if (ff_pkt->flags & FO_ACL) {
1416             for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1417                if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1418                   skip_xattr = true;
1419                   break;
1420                }
1421             }
1422          }
1423
1424          /*
1425           * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1426           */
1427          if (!skip_xattr) {
1428             for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1429                if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1430                   skip_xattr = true;
1431                   break;
1432                }
1433             }
1434          }
1435
1436          if (skip_xattr) {
1437             Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1438             continue;
1439          }
1440
1441          /*
1442           * Each xattr valuepair starts with a magic so we can parse it easier.
1443           */
1444          current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1445          current_xattr->magic = XATTR_MAGIC;
1446          expected_serialize_len += sizeof(current_xattr->magic);
1447
1448          /*
1449           * Allocate space for storing the name.
1450           */
1451          current_xattr->name_length = strlen(current_attrtuple);
1452          current_xattr->name = (char *)malloc(current_xattr->name_length);
1453          memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
1454
1455          expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1456
1457          /*
1458           * First see how long the value is for the extended attribute.
1459           */
1460          xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
1461          switch (xattr_value_len) {
1462          case -1:
1463             switch (errno) {
1464             case ENOENT:
1465                retval = bxattr_exit_ok;
1466                goto bail_out;
1467             default:
1468                Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1469                      jcr->last_fname, be.bstrerror());
1470                Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1471                      jcr->last_fname, be.bstrerror());
1472                goto bail_out;
1473             }
1474             break;
1475          case 0:
1476             current_xattr->value = NULL;
1477             current_xattr->value_length = 0;
1478             expected_serialize_len += sizeof(current_xattr->value_length);
1479             break;
1480          default:
1481             /*
1482              * Allocate space for storing the value.
1483              */
1484             current_xattr->value = (char *)malloc(xattr_value_len);
1485             memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1486
1487             xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
1488             if (xattr_value_len < 0) {
1489                switch (errno) {
1490                case ENOENT:
1491                   retval = bxattr_exit_ok;
1492                   goto bail_out;
1493                default:
1494                   Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1495                         jcr->last_fname, be.bstrerror());
1496                   Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1497                         jcr->last_fname, be.bstrerror());
1498                   goto bail_out;
1499                }
1500             }
1501
1502             /*
1503              * Store the actual length of the value.
1504              */
1505             current_xattr->value_length = xattr_value_len;
1506             expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1507
1508             /*
1509              * Protect ourself against things getting out of hand.
1510              */
1511             if (expected_serialize_len >= MAX_XATTR_STREAM) {
1512                Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1513                      jcr->last_fname, MAX_XATTR_STREAM);
1514                goto bail_out;
1515             }
1516             break;
1517          }
1518
1519          if (xattr_value_list == NULL) {
1520             xattr_value_list = New(alist(10, not_owned_by_alist));
1521          }
1522
1523          xattr_value_list->append(current_xattr);
1524          current_xattr = NULL;
1525          xattr_count++;
1526
1527       }
1528
1529       /*
1530        * Drop the local copy of the current_attrnamespace.
1531        */
1532       actuallyfree(current_attrnamespace);
1533       current_attrnamespace = NULL;
1534
1535       /*
1536        * We are done with this xattr list.
1537        */
1538       free(xattr_list);
1539       xattr_list = (char *)NULL;
1540    }
1541
1542    /*
1543     * If we found any xattr send them to the SD.
1544     */
1545    if (xattr_count > 0) {
1546       /*
1547        * Serialize the datastream.
1548        */
1549       if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1550          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1551                jcr->last_fname);
1552          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1553                jcr->last_fname);
1554          goto bail_out;
1555       }
1556
1557       /*
1558        * Send the datastream to the SD.
1559        */
1560       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1561    } else {
1562       retval = bxattr_exit_ok;
1563    }
1564
1565 bail_out:
1566    if (current_attrnamespace != NULL) {
1567       actuallyfree(current_attrnamespace);
1568    }
1569    if (current_xattr != NULL) {
1570       if (current_xattr->value != NULL) {
1571          free(current_xattr->value);
1572       }
1573       if (current_xattr->name != NULL) {
1574          free(current_xattr->name);
1575       }
1576       free(current_xattr);
1577    }
1578    if (xattr_list != NULL) {
1579       free(xattr_list);
1580    }
1581    if (xattr_value_list != NULL) {
1582       xattr_drop_internal_table(xattr_value_list);
1583    }
1584    return retval;
1585 }
1586
1587 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
1588 {
1589    xattr_t *current_xattr;
1590    alist *xattr_value_list;
1591    int current_attrnamespace, cnt;
1592    char *attrnamespace, *attrname;
1593    berrno be;
1594
1595    xattr_value_list = New(alist(10, not_owned_by_alist));
1596
1597    if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1598       xattr_drop_internal_table(xattr_value_list);
1599       return bxattr_exit_error;
1600    }
1601
1602    foreach_alist(current_xattr, xattr_value_list) {
1603       /*
1604        * Try splitting the xattr_name into a namespace and name part.
1605        * The splitting character is a .
1606        */
1607       attrnamespace = current_xattr->name;
1608       if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1609          Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1610                current_xattr->name, jcr->last_fname);
1611          Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1612                current_xattr->name, jcr->last_fname);
1613          goto bail_out;
1614       }
1615       *attrname++ = '\0';
1616
1617       /*
1618        * Make sure the attrnamespace makes sense.
1619        */
1620       if (extattr_string_to_namespace(attrnamespace, &current_attrnamespace) != 0) {
1621          Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1622                attrnamespace, jcr->last_fname);
1623          Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1624                attrnamespace, jcr->last_fname);
1625          goto bail_out;
1626       }
1627
1628       /*
1629        * Try restoring the extended attribute.
1630        */
1631       cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1632                              attrname, current_xattr->value, current_xattr->value_length);
1633       if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1634          switch (errno) {
1635          case ENOENT:
1636             goto bail_out;
1637             break;
1638          default:
1639             Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1640                   jcr->last_fname, be.bstrerror());
1641             Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1642                   jcr->last_fname, be.bstrerror());
1643             goto bail_out;
1644             break;
1645          }
1646       }
1647    }
1648
1649    xattr_drop_internal_table(xattr_value_list);
1650    return bxattr_exit_ok;
1651
1652 bail_out:
1653    xattr_drop_internal_table(xattr_value_list);
1654    return bxattr_exit_error;
1655 }
1656
1657 /*
1658  * Function pointers to the build and parse function to use for these xattrs.
1659  */
1660 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1661 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1662
1663 #elif defined(HAVE_OSF1_OS)
1664
1665 #if !defined(HAVE_GETPROPLIST) || \
1666     !defined(HAVE_GET_PROPLIST_ENTRY) || \
1667     !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1668     !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1669     !defined(HAVE_SETPROPLIST)
1670 #error "Missing full support for the Extended Attributes functions."
1671 #endif
1672
1673 #ifdef HAVE_SYS_PROPLIST_H
1674 #include <sys/proplist.h>
1675 #else
1676 #error "Missing sys/proplist.h header file"
1677 #endif
1678
1679 /*
1680  * Define the supported XATTR streams for this OS
1681  */
1682 static int os_default_xattr_streams[1] = { STREAM_XATTR_TRU64 };
1683 static const char *xattr_acl_skiplist[1] = { NULL };
1684 static const char *xattr_skiplist[1] = { NULL };
1685
1686 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1687 {
1688    int cnt;
1689    char *bp,
1690         *xattr_name,
1691         *xattr_value;
1692    bool skip_xattr;
1693    int xattr_count = 0;
1694    int32_t *flags,
1695            *xattr_value_len;
1696    int32_t xattr_list_len,
1697            xattrbuf_size,
1698            xattrbuf_min_size;
1699    uint32_t expected_serialize_len = 0;
1700    xattr_t *current_xattr = NULL;
1701    alist *xattr_value_list = NULL;
1702    struct proplistname_args prop_args;
1703    bxattr_exit_code retval = bxattr_exit_error;
1704    POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1705    berrno be;
1706
1707    xattrbuf_size = sizeof_pool_memory(xattrbuf);
1708    xattrbuf_min_size = 0;
1709    xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1710                                 xattrbuf, &xattrbuf_min_size);
1711
1712    /*
1713     * See what xattr are available.
1714     */
1715    switch (xattr_list_len) {
1716    case -1:
1717       switch (errno) {
1718       case EOPNOTSUPP:
1719          retval = bxattr_exit_ok;
1720          goto bail_out;
1721       default:
1722          Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1723                jcr->last_fname, be.bstrerror());
1724          Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1725                jcr->last_fname, be.bstrerror());
1726          goto bail_out;
1727       }
1728       break;
1729    case 0:
1730       if (xattrbuf_min_size) {
1731          /*
1732           * The buffer isn't big enough to hold the xattr data, we now have
1733           * a minimum buffersize so we resize the buffer and try again.
1734           */
1735          xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1736          xattrbuf_size = xattrbuf_min_size + 1;
1737          xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1738                                    xattrbuf, &xattrbuf_min_size);
1739          switch (xattr_list_len) {
1740          case -1:
1741             switch (errno) {
1742             case EOPNOTSUPP:
1743                retval = bxattr_exit_ok;
1744                goto bail_out;
1745             default:
1746                Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1747                      jcr->last_fname, be.bstrerror());
1748                Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1749                      jcr->last_fname, be.bstrerror());
1750                goto bail_out;
1751             }
1752             break;
1753          case 0:
1754             /*
1755              * This should never happen as we sized the buffer according to the minimumsize
1756              * returned by a previous getproplist call. If it does happen things are fishy and
1757              * we are better of forgetting this xattr as it seems its list is changing at this
1758              * exact moment so we can never make a good backup copy of it.
1759              */
1760             retval = bxattr_exit_ok;
1761             goto bail_out;
1762          default:
1763             break;
1764          }
1765       } else {
1766          /**
1767           * No xattr on file.
1768           */
1769          retval = bxattr_exit_ok;
1770          goto bail_out;
1771       }
1772       break;
1773    default:
1774       break;
1775    }
1776
1777    /*
1778     * Walk the list of extended attributes names and retrieve the data.
1779     * We already count the bytes needed for serializing the stream later on.
1780     */
1781    bp = xattrbuf;
1782    while (xattrbuf_size > 0) {
1783       /*
1784        * Call getproplist_entry to initialize name and value
1785        * pointers to entries position within buffer.
1786        */
1787       xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
1788
1789       /*
1790        * On some OSes you also get the acls in the extented attribute list.
1791        * So we check if we are already backing up acls and if we do we
1792        * don't store the extended attribute with the same info.
1793        */
1794       if (ff_pkt->flags & FO_ACL) {
1795          for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1796             if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
1797                skip_xattr = true;
1798                break;
1799             }
1800          }
1801       }
1802
1803       /*
1804        * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1805        */
1806       if (!skip_xattr) {
1807          for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1808             if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
1809                skip_xattr = true;
1810                break;
1811             }
1812          }
1813       }
1814
1815       if (skip_xattr) {
1816          Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
1817          continue;
1818       }
1819
1820       /*
1821        * Each xattr valuepair starts with a magic so we can parse it easier.
1822        */
1823       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1824       current_xattr->magic = XATTR_MAGIC;
1825       expected_serialize_len += sizeof(current_xattr->magic);
1826
1827       current_xattr->name_length = strlen(xattr_name);
1828       current_xattr->name = bstrdup(xattr_name);
1829
1830       expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1831
1832       current_xattr->value_length = *xattr_value_len;
1833       current_xattr->value = (char *)malloc(current_xattr->value_length);
1834       memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
1835
1836       expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1837
1838       /*
1839        * Protect ourself against things getting out of hand.
1840        */
1841       if (expected_serialize_len >= MAX_XATTR_STREAM) {
1842          Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1843                jcr->last_fname, MAX_XATTR_STREAM);
1844          goto bail_out;
1845       }
1846
1847       if (xattr_value_list == NULL) {
1848          xattr_value_list = New(alist(10, not_owned_by_alist));
1849       }
1850
1851       xattr_value_list->append(current_xattr);
1852       current_xattr = NULL;
1853       xattr_count++;
1854    }
1855
1856    /*
1857     * If we found any xattr send them to the SD.
1858     */
1859    if (xattr_count > 0) {
1860       /*
1861        * Serialize the datastream.
1862        */
1863       if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1864          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1865                jcr->last_fname);
1866          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1867                jcr->last_fname);
1868          goto bail_out;
1869       }
1870
1871       /*
1872        * Send the datastream to the SD.
1873        */
1874       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1875    }
1876
1877 bail_out:
1878    if (current_xattr != NULL) {
1879       if (current_xattr->value != NULL) {
1880          free(current_xattr->value);
1881       }
1882       if (current_xattr->name != NULL) {
1883          free(current_xattr->name);
1884       }
1885       free(current_xattr);
1886    }
1887    if (xattr_value_list != NULL) {
1888       xattr_drop_internal_table(xattr_value_list);
1889    }
1890    free_pool_memory(xattrbuf);
1891
1892    return retval;
1893 }
1894
1895 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr, int stream)
1896 {
1897    char *bp, *xattrbuf = NULL;
1898    int32_t xattrbuf_size, cnt;
1899    xattr_t *current_xattr;
1900    alist *xattr_value_list;
1901    bxattr_exit_code retval = bxattr_exit_error;
1902    berrno be;
1903
1904    xattr_value_list = New(alist(10, not_owned_by_alist));
1905
1906    if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1907       xattr_drop_internal_table(xattr_value_list);
1908       return bxattr_exit_error;
1909    }
1910
1911    /*
1912     * See how big the propertylist must be.
1913     */
1914    xattrbuf_size = 0;
1915    foreach_alist(current_xattr, xattr_value_list) {
1916       xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
1917    }
1918
1919    xattrbuf = (char *)malloc(xattrbuf_size);
1920
1921    /*
1922     * Add all value pairs to the proplist.
1923     */
1924    cnt = 0;
1925    bp = xattrbuf;
1926    foreach_alist(current_xattr, xattr_value_list) {
1927       cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
1928                                current_xattr->value, &bp);
1929    }
1930
1931    /*
1932     * Sanity check.
1933     */
1934    if (cnt != xattrbuf_size) {
1935       Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
1936             jcr->last_fname);
1937       Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
1938             jcr->last_fname);
1939       goto bail_out;
1940    }
1941
1942    /*
1943     * Restore the list of extended attributes on the file.
1944     */
1945    cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
1946    switch (cnt) {
1947    case -1:
1948       switch (errno) {
1949       case EOPNOTSUPP:
1950          retval = bxattr_exit_ok;
1951          goto bail_out;
1952       default:
1953          Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
1954                jcr->last_fname, be.bstrerror());
1955          Dmsg2(100, "setproplist error file=%s ERR=%s\n",
1956                jcr->last_fname, be.bstrerror());
1957          goto bail_out;
1958       }
1959       break;
1960    default:
1961       break;
1962    }
1963
1964    free(xattrbuf);
1965
1966    xattr_drop_internal_table(xattr_value_list);
1967    return bxattr_exit_ok;
1968
1969 bail_out:
1970    if (xattrbuf) {
1971       free(xattrbuf);
1972    }
1973    xattr_drop_internal_table(xattr_value_list);
1974    return bxattr_exit_error;
1975 }
1976
1977 /*
1978  * Function pointers to the build and parse function to use for these xattrs.
1979  */
1980 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_xattr_streams;
1981 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = tru64_parse_xattr_streams;
1982
1983 #elif defined(HAVE_SUN_OS)
1984 /*
1985  * Solaris extended attributes were introduced in Solaris 9
1986  * by PSARC 1999/209
1987  *
1988  * Solaris extensible attributes were introduced in OpenSolaris
1989  * by PSARC 2007/315 Solaris extensible attributes are also
1990  * sometimes called extended system attributes.
1991  *
1992  * man fsattr(5) on Solaris gives a wealth of info. The most
1993  * important bits are:
1994  *
1995  * Attributes are logically supported as files within the  file
1996  * system.   The  file  system  is  therefore augmented with an
1997  * orthogonal name space of file attributes. Any file  (includ-
1998  * ing  attribute files) can have an arbitrarily deep attribute
1999  * tree associated with it. Attribute values  are  accessed  by
2000  * file descriptors obtained through a special attribute inter-
2001  * face.  This logical view of "attributes as files" allows the
2002  * leveraging  of  existing file system interface functionality
2003  * to support the construction, deletion, and  manipulation  of
2004  * attributes.
2005  *
2006  * The special files  "."  and  ".."  retain  their  accustomed
2007  * semantics within the attribute hierarchy.  The "." attribute
2008  * file refers to the current directory and the ".."  attribute
2009  * file  refers to the parent directory.  The unnamed directory
2010  * at the head of each attribute tree is considered the "child"
2011  * of  the  file it is associated with and the ".." file refers
2012  * to the associated file.  For  any  non-directory  file  with
2013  * attributes,  the  ".." entry in the unnamed directory refers
2014  * to a file that is not a directory.
2015  *
2016  * Conceptually, the attribute model is fully general. Extended
2017  * attributes  can  be  any  type of file (doors, links, direc-
2018  * tories, and so forth) and can even have their own attributes
2019  * (fully  recursive).   As a result, the attributes associated
2020  * with a file could be an arbitrarily deep directory hierarchy
2021  * where each attribute could have an equally complex attribute
2022  * tree associated with it.  Not all implementations  are  able
2023  * to,  or  want to, support the full model. Implementation are
2024  * therefore permitted to reject operations that are  not  sup-
2025  * ported.   For  example,  the implementation for the UFS file
2026  * system allows only regular files as attributes (for example,
2027  * no sub-directories) and rejects attempts to place attributes
2028  * on attributes.
2029  *
2030  * The following list details the operations that are  rejected
2031  * in the current implementation:
2032  *
2033  * link                     Any attempt to create links between
2034  *                          attribute  and  non-attribute space
2035  *                          is rejected  to  prevent  security-
2036  *                          related   or   otherwise  sensitive
2037  *                          attributes from being exposed,  and
2038  *                          therefore  manipulable,  as regular
2039  *                          files.
2040  *
2041  * rename                   Any  attempt  to   rename   between
2042  *                          attribute  and  non-attribute space
2043  *                          is rejected to prevent  an  already
2044  *                          linked  file from being renamed and
2045  *                          thereby circumventing the link res-
2046  *                          triction above.
2047  *
2048  * mkdir, symlink, mknod    Any  attempt  to  create  a   "non-
2049  *                          regular" file in attribute space is
2050  *                          rejected to reduce the  functional-
2051  *                          ity,  and  therefore  exposure  and
2052  *                          risk, of  the  initial  implementa-
2053  *                          tion.
2054  *
2055  * The entire available name space has been allocated to  "gen-
2056  * eral use" to bring the implementation in line with the NFSv4
2057  * draft standard [NFSv4]. That standard defines "named  attri-
2058  * butes"  (equivalent  to Solaris Extended Attributes) with no
2059  * naming restrictions.  All Sun  applications  making  use  of
2060  * opaque extended attributes will use the prefix "SUNW".
2061  *
2062  */
2063 #ifdef HAVE_SYS_ATTR_H
2064 #include <sys/attr.h>
2065 #endif
2066
2067 #ifdef HAVE_ATTR_H
2068 #include <attr.h>
2069 #endif
2070
2071 #ifdef HAVE_SYS_NVPAIR_H
2072 #include <sys/nvpair.h>
2073 #endif
2074
2075 #ifdef HAVE_SYS_ACL_H
2076 #include <sys/acl.h>
2077 #endif
2078
2079 #if !defined(HAVE_OPENAT) || \
2080     !defined(HAVE_UNLINKAT) || \
2081     !defined(HAVE_FCHOWNAT) || \
2082     !defined(HAVE_FUTIMESAT)
2083 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2084 #endif
2085
2086 /*
2087  * Define the supported XATTR streams for this OS
2088  */
2089 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2090 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
2091 #else
2092 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
2093 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2094
2095 /*
2096  * This code creates a temporary cache with entries for each xattr which has
2097  * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2098  */
2099 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2100 {
2101    xattr_link_cache_entry_t *ptr;
2102
2103    foreach_alist(ptr, jcr->xattr_data->link_cache) {
2104       if (ptr && ptr->inum == inum) {
2105          return ptr;
2106       }
2107    }
2108    return NULL;
2109 }
2110
2111 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2112 {
2113    xattr_link_cache_entry_t *ptr;
2114
2115    ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2116    memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
2117    ptr->inum = inum;
2118    bstrncpy(ptr->target, target, sizeof(ptr->target));
2119    jcr->xattr_data->link_cache->append(ptr);
2120 }
2121
2122 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2123 /*
2124  * This function returns true if a non default extended system attribute
2125  * list is associated with fd and returns false when an error has occured
2126  * or when only extended system attributes other than archive,
2127  * av_modified or crtime are set.
2128  *
2129  * The function returns true for the following cases:
2130  *
2131  * - any extended system attribute other than the default attributes
2132  *   ('archive', 'av_modified' and 'crtime') is set
2133  * - nvlist has NULL name string
2134  * - nvpair has data type of 'nvlist'
2135  * - default data type.
2136  */
2137 static bool solaris_has_non_transient_extensible_attributes(int fd)
2138 {
2139    boolean_t value;
2140    data_type_t type;
2141    nvlist_t *response;
2142    nvpair_t *pair;
2143    f_attr_t fattr;
2144    char *name;
2145    bool retval = false;
2146
2147    if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2148       return false;
2149    }
2150
2151    pair = NULL;
2152    while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2153       name = nvpair_name(pair);
2154
2155       if (name != NULL) {
2156          fattr = name_to_attr(name);
2157       } else {
2158          retval = true;
2159          goto bail_out;
2160       }
2161
2162       type = nvpair_type(pair);
2163       switch (type) {
2164       case DATA_TYPE_BOOLEAN_VALUE:
2165          if (nvpair_value_boolean_value(pair, &value) != 0) {
2166             continue;
2167          }
2168          if (value && fattr != F_ARCHIVE &&
2169                       fattr != F_AV_MODIFIED) {
2170             retval = true;
2171             goto bail_out;
2172          }
2173          break;
2174       case DATA_TYPE_UINT64_ARRAY:
2175          if (fattr != F_CRTIME) {
2176             retval = true;
2177             goto bail_out;
2178          }
2179          break;
2180       case DATA_TYPE_NVLIST:
2181       default:
2182          retval = true;
2183          goto bail_out;
2184       }
2185    }
2186
2187 bail_out:
2188    if (response != NULL) {
2189       nvlist_free(response);
2190    }
2191    return retval;
2192 }
2193 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2194
2195 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2196 /*
2197  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2198  * There is no need to store those acls as we already store the stat bits too.
2199  */
2200 static bool acl_is_trivial(int count, aclent_t *entries)
2201 {
2202    int n;
2203    aclent_t *ace;
2204
2205    for (n = 0; n < count; n++) {
2206       ace = &entries[n];
2207       if (!(ace->a_type == USER_OBJ ||
2208             ace->a_type == GROUP_OBJ ||
2209             ace->a_type == OTHER_OBJ ||
2210             ace->a_type == CLASS_OBJ))
2211         return false;
2212    }
2213    return true;
2214 }
2215 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2216
2217 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2218 {
2219 #ifdef HAVE_ACL
2220 #ifdef HAVE_EXTENDED_ACL
2221    int flags;
2222    acl_t *aclp = NULL;
2223    berrno be;
2224
2225    /*
2226     * See if this attribute has an ACL
2227     */
2228    if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2229        pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2230       /*
2231        * See if there is a non trivial acl on the file.
2232        */
2233       if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2234            acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2235          switch (errno) {
2236          case ENOENT:
2237             return bxattr_exit_ok;
2238          default:
2239             Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2240                   attrname, jcr->last_fname, be.bstrerror());
2241             Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2242                   attrname, jcr->last_fname, be.bstrerror());
2243             return bxattr_exit_error;
2244          }
2245       }
2246
2247       if (aclp != NULL) {
2248 #if defined(ACL_SID_FMT)
2249          /*
2250           * New format flag added in newer Solaris versions.
2251           */
2252          flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2253 #else
2254          flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2255 #endif /* ACL_SID_FMT */
2256
2257          *acl_text = acl_totext(aclp, flags);
2258          acl_free(aclp);
2259       } else {
2260          *acl_text = NULL;
2261       }
2262    } else {
2263       *acl_text = NULL;
2264    }
2265    return bxattr_exit_ok;
2266 #else /* HAVE_EXTENDED_ACL */
2267    int n;
2268    aclent_t *acls = NULL;
2269    berrno be;
2270
2271    /*
2272     * See if this attribute has an ACL
2273     */
2274    if (fd != -1) {
2275       n = facl(fd, GETACLCNT, 0, NULL);
2276    } else {
2277       n = acl(attrname, GETACLCNT, 0, NULL);
2278    }
2279
2280    if (n >= MIN_ACL_ENTRIES) {
2281       acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2282       if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2283           acl(attrname, GETACL, n, acls) != n) {
2284          switch (errno) {
2285          case ENOENT:
2286             free(acls);
2287             return bxattr_exit_ok;
2288          default:
2289             Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2290                   attrname, jcr->last_fname, be.bstrerror());
2291             Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2292                   attrname, jcr->last_fname, be.bstrerror());
2293             free(acls);
2294             return bxattr_exit_error;
2295          }
2296       }
2297
2298       /*
2299        * See if there is a non trivial acl on the file.
2300        */
2301       if (!acl_is_trivial(n, acls)) {
2302          if ((*acl_text = acltotext(acls, n)) == NULL) {
2303             Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2304                   attrname, jcr->last_fname, be.bstrerror());
2305             Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2306                   attrname, jcr->last_fname, be.bstrerror());
2307             free(acls);
2308             return bxattr_exit_error;
2309          }
2310       } else {
2311          *acl_text = NULL;
2312       }
2313
2314      free(acls);
2315    } else {
2316       *acl_text = NULL;
2317    }
2318    return bxattr_exit_ok;
2319 #endif /* HAVE_EXTENDED_ACL */
2320
2321 #else /* HAVE_ACL */
2322    return bxattr_exit_ok;
2323 #endif /* HAVE_ACL */
2324 }
2325
2326 /*
2327  * Forward declaration for recursive function call.
2328  */
2329 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2330
2331 /*
2332  * Save an extended or extensible attribute.
2333  * This is stored as an opaque stream of bytes with the following encoding:
2334  *
2335  * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2336  * 
2337  * or for a hardlinked or symlinked attribute
2338  *
2339  * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2340  *
2341  * xattr_name can be a subpath relative to the file the xattr is on.
2342  * stat_buffer is the string representation of the stat struct.
2343  * acl_string is an acl text when a non trivial acl is set on the xattr.
2344  * actual_xattr_data is the content of the xattr file.
2345  */
2346 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2347                                            const char *attrname, bool toplevel_hidden_dir, int stream)
2348 {
2349    int cnt;
2350    int attrfd = -1;
2351    struct stat st;
2352    xattr_link_cache_entry_t *xlce;
2353    char target_attrname[PATH_MAX];
2354    char link_source[PATH_MAX];
2355    char *acl_text = NULL;
2356    char attribs[MAXSTRING];
2357    char buffer[XATTR_BUFSIZ];
2358    bxattr_exit_code retval = bxattr_exit_error;
2359    berrno be;
2360
2361    bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2362
2363    /*
2364     * Get the stats of the extended or extensible attribute.
2365     */
2366    if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2367       switch (errno) {
2368       case ENOENT:
2369          retval = bxattr_exit_ok;
2370          goto bail_out;
2371       default:
2372          Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2373                target_attrname, jcr->last_fname, be.bstrerror());
2374          Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2375                target_attrname, jcr->last_fname, be.bstrerror());
2376          goto bail_out;
2377       }
2378    }
2379
2380    /*
2381     * Based on the filetype perform the correct action. We support most filetypes here, more
2382     * then the actual implementation on Solaris supports so some code may never get executed
2383     * due to limitations in the implementation.
2384     */
2385    switch (st.st_mode & S_IFMT) {
2386    case S_IFIFO:
2387    case S_IFCHR:
2388    case S_IFBLK:
2389       /*
2390        * Get any acl on the xattr.
2391        */
2392       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2393          goto bail_out;
2394
2395       /*
2396        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2397        * Encode the stat struct into an ASCII representation.
2398        */
2399       encode_stat(attribs, &st, 0, stream);
2400       cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2401                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2402       break;
2403    case S_IFDIR:
2404       /*
2405        * Get any acl on the xattr.
2406        */
2407       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2408          goto bail_out;
2409
2410       /*
2411        * See if this is the toplevel_hidden_dir being saved.
2412        */
2413       if (toplevel_hidden_dir) {
2414          /*
2415           * Save the data for later storage when we encounter a real xattr. We store the data
2416           * in the jcr->xattr_data->content buffer and flush that just before sending out the
2417           * first real xattr. Encode the stat struct into an ASCII representation and jump
2418           * out of the function.
2419           */
2420          encode_stat(attribs, &st, 0, stream);
2421          cnt = bsnprintf(buffer, sizeof(buffer),
2422                          "%s%c%s%c%s%c",
2423                          target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2424          pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2425          jcr->xattr_data->content_length = cnt;
2426          goto bail_out;
2427       } else {
2428          /*
2429           * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2430           * Encode the stat struct into an ASCII representation.
2431           */
2432          encode_stat(attribs, &st, 0, stream);
2433          cnt = bsnprintf(buffer, sizeof(buffer),
2434                          "%s%c%s%c%s%c",
2435                          target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2436       }
2437       break;
2438    case S_IFREG:
2439       /*
2440        * If this is a hardlinked file check the inode cache for a hit.
2441        */
2442       if (st.st_nlink > 1) {
2443          /*
2444           * See if the cache already knows this inode number.
2445           */
2446          if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2447             /*
2448              * Generate a xattr encoding with the reference to the target in there.
2449              */
2450             encode_stat(attribs, &st, st.st_ino, stream);
2451             cnt = bsnprintf(buffer, sizeof(buffer),
2452                             "%s%c%s%c%s%c",
2453                             target_attrname, 0, attribs, 0, xlce->target, 0);
2454             pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2455             jcr->xattr_data->content_length = cnt;
2456             retval = send_xattr_stream(jcr, stream);
2457
2458             /*
2459              * For a hard linked file we are ready now, no need to recursively save the attributes.
2460              */
2461             goto bail_out;
2462          }
2463
2464          /*
2465           * Store this hard linked file in the cache.
2466           * Store the name relative to the top level xattr space.
2467           */
2468          add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2469       }
2470
2471       /*
2472        * Get any acl on the xattr.
2473        */
2474       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2475          goto bail_out;
2476       }
2477
2478       /*
2479        * Encode the stat struct into an ASCII representation.
2480        */
2481       encode_stat(attribs, &st, 0, stream);
2482       cnt = bsnprintf(buffer, sizeof(buffer),
2483                      "%s%c%s%c%s%c",
2484                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2485
2486       /*
2487        * Open the extended or extensible attribute file.
2488        */
2489       if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2490          switch (errno) {
2491          case ENOENT:
2492             retval = bxattr_exit_ok;
2493             goto bail_out;
2494          default:
2495             Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2496                   target_attrname, jcr->last_fname, be.bstrerror());
2497             Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2498                   target_attrname, jcr->last_fname, be.bstrerror());
2499             goto bail_out;
2500          }
2501       }
2502       break;
2503    case S_IFLNK:
2504       /*
2505        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2506        * Encode the stat struct into an ASCII representation.
2507        */
2508       if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2509          switch (errno) {
2510          case ENOENT:
2511             retval = bxattr_exit_ok;
2512             goto bail_out;
2513          default:
2514             Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2515                   target_attrname, jcr->last_fname, be.bstrerror());
2516             Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2517                   target_attrname, jcr->last_fname, be.bstrerror());
2518             goto bail_out;
2519          }
2520       }
2521
2522       /*
2523        * Generate a xattr encoding with the reference to the target in there.
2524        */
2525       encode_stat(attribs, &st, st.st_ino, stream);
2526       cnt = bsnprintf(buffer, sizeof(buffer),
2527                       "%s%c%s%c%s%c",
2528                       target_attrname, 0, attribs, 0, link_source, 0);
2529       pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2530       jcr->xattr_data->content_length = cnt;
2531       retval = send_xattr_stream(jcr, stream);
2532
2533       if (retval == bxattr_exit_ok) {
2534          jcr->xattr_data->nr_saved++;
2535       }
2536
2537       /*
2538        * For a soft linked file we are ready now, no need to recursively save the attributes.
2539        */
2540       goto bail_out;
2541    default:
2542       goto bail_out;
2543    }
2544
2545    /*
2546     * See if this is the first real xattr being saved.
2547     * If it is save the toplevel_hidden_dir attributes first.
2548     * This is easy as its stored already in the jcr->xattr_data->content buffer.
2549     */
2550    if (jcr->xattr_data->nr_saved == 0) {
2551       retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2552       if (retval != bxattr_exit_ok) {
2553          goto bail_out;
2554       }
2555       jcr->xattr_data->nr_saved++;
2556    }
2557
2558    pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2559    jcr->xattr_data->content_length = cnt;
2560
2561    /*
2562     * Only dump the content of regular files.
2563     */
2564    switch (st.st_mode & S_IFMT) {
2565    case S_IFREG:
2566       if (st.st_size > 0) {
2567          /*
2568           * Protect ourself against things getting out of hand.
2569           */
2570          if (st.st_size >= MAX_XATTR_STREAM) {
2571             Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2572                   jcr->last_fname, MAX_XATTR_STREAM);
2573             goto bail_out;
2574          }
2575
2576          while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2577             jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
2578             memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
2579             jcr->xattr_data->content_length += cnt;
2580          }
2581
2582          if (cnt < 0) {
2583             Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
2584                   target_attrname, jcr->last_fname);
2585             Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2586                   target_attrname, jcr->last_fname);
2587             goto bail_out;
2588          }
2589       }
2590       break;
2591
2592    default:
2593       break;
2594    }
2595
2596    if (retval) {
2597       retval = send_xattr_stream(jcr, stream);
2598       if (retval == bxattr_exit_ok) {
2599          jcr->xattr_data->nr_saved++;
2600       }
2601    }
2602
2603    /*
2604     * Recursivly call solaris_save_extended_attributes for archiving the attributes
2605     * available on this extended attribute.
2606     */
2607    if (retval) {
2608       retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2609       
2610       /*
2611        * The recursive call could change our working dir so change back to the wanted workdir.
2612        */
2613       if (fchdir(fd) < 0) {
2614          switch (errno) {
2615          case ENOENT:
2616             retval = bxattr_exit_ok;
2617             goto bail_out;
2618          default:
2619             Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2620                   jcr->last_fname, be.bstrerror());
2621             Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2622                   jcr->last_fname, fd, be.bstrerror());
2623             goto bail_out;
2624          }
2625       }
2626    }
2627
2628 bail_out:
2629    if (acl_text != NULL) {
2630       free(acl_text);
2631    }
2632    if (attrfd != -1) {
2633       close(attrfd);
2634    }
2635    return retval;
2636 }
2637
2638 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2639 {
2640    const char *name;
2641    int fd, filefd = -1, attrdirfd = -1;
2642    DIR *dirp;
2643    struct dirent *dp;
2644    char current_xattr_namespace[PATH_MAX];
2645    bxattr_exit_code retval = bxattr_exit_error;
2646    berrno be;
2647  
2648    /*
2649     * Determine what argument to use. Use attr_parent when set
2650     * (recursive call) or jcr->last_fname for first call. Also save
2651     * the current depth of the xattr_space we are in.
2652     */
2653    if (attr_parent) {
2654       name = attr_parent;
2655       if (xattr_namespace) {
2656          bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2657                    xattr_namespace, attr_parent);
2658       } else {
2659          bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2660       }
2661    } else {
2662       name = jcr->last_fname;
2663       bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2664    }
2665
2666    /*
2667     * Open the file on which to save the xattrs read-only.
2668     */
2669    if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2670       switch (errno) {
2671       case ENOENT:
2672          retval = bxattr_exit_ok;
2673          goto bail_out;
2674       default:
2675          Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2676                jcr->last_fname, be.bstrerror());
2677          Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2678                jcr->last_fname, be.bstrerror());
2679          goto bail_out;
2680       }
2681    }
2682
2683    /*
2684     * Open the xattr naming space.
2685     */
2686    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2687       switch (errno) {
2688       case EINVAL:
2689          /*
2690           * Gentile way of the system saying this type of xattr layering is not supported.
2691           * Which is not problem we just forget about this this xattr.
2692           * But as this is not an error we return a positive return value.
2693           */
2694          retval = bxattr_exit_ok;
2695          goto bail_out;
2696       case ENOENT:
2697          retval = bxattr_exit_ok;
2698          goto bail_out;
2699       default:
2700          Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2701                name, jcr->last_fname, be.bstrerror());
2702          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2703                name, jcr->last_fname, be.bstrerror());
2704          goto bail_out;
2705       }
2706    }
2707
2708   /*
2709    * We need to change into the attribute directory to determine if each of the
2710    * attributes should be saved.
2711    */
2712    if (fchdir(attrdirfd) < 0) {
2713       Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2714             jcr->last_fname, be.bstrerror());
2715       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2716             jcr->last_fname, attrdirfd, be.bstrerror());
2717       goto bail_out;
2718    }
2719
2720    /*
2721     * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2722     * else because the readdir returns "." entry after the extensible attr entry.
2723     * And as we want this entry before anything else we better just save its data.
2724     */
2725    if (!attr_parent)
2726       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2727                          true, STREAM_XATTR_SOLARIS);
2728
2729    if ((fd = dup(attrdirfd)) == -1 ||
2730        (dirp = fdopendir(fd)) == (DIR *)NULL) {
2731       Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2732             jcr->last_fname, be.bstrerror());
2733       Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
2734             jcr->last_fname, fd, be.bstrerror());
2735
2736       goto bail_out;
2737    }
2738
2739    /*
2740     * Walk the namespace.
2741     */
2742    while ((dp = readdir(dirp)) != NULL) {
2743       /*
2744        * Skip only the toplevel . dir.
2745        */
2746       if (!attr_parent && bstrcmp(dp->d_name, "."))
2747          continue;
2748
2749       /*
2750        * Skip all .. directories
2751        */
2752       if (bstrcmp(dp->d_name, ".."))
2753          continue;
2754
2755       Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2756          current_xattr_namespace, dp->d_name, jcr->last_fname);
2757
2758 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2759       /*
2760        * We are not interested in read-only extensible attributes.
2761        */
2762       if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2763          Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2764             current_xattr_namespace, dp->d_name, jcr->last_fname);
2765
2766          continue;
2767       }
2768
2769       /*
2770        * We are only interested in read-write extensible attributes
2771        * when they contain non-transient values.
2772        */
2773       if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2774          /*
2775           * Determine if there are non-transient system attributes at the toplevel.
2776           * We need to provide a fd to the open file.
2777           */
2778          if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2779             Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2780                current_xattr_namespace, dp->d_name, jcr->last_fname);
2781             continue;
2782          }
2783
2784          /*
2785           * Save the xattr.
2786           */
2787          solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2788                             false, STREAM_XATTR_SOLARIS_SYS);
2789          continue;
2790       }
2791 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2792
2793       /*
2794        * Save the xattr.
2795        */
2796       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2797                          false, STREAM_XATTR_SOLARIS);
2798    }
2799
2800    closedir(dirp);
2801    retval = bxattr_exit_ok;
2802
2803 bail_out:
2804    if (attrdirfd != -1)
2805       close(attrdirfd);
2806    if (filefd != -1)
2807       close(filefd);
2808    return retval;
2809 }
2810
2811 #ifdef HAVE_ACL
2812 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
2813 {
2814 #ifdef HAVE_EXTENDED_ACL
2815    int error;
2816    acl_t *aclp = NULL;
2817    berrno be;
2818
2819    if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
2820       Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
2821             jcr->last_fname);
2822       return bxattr_exit_error;
2823    }
2824
2825    if ((fd != -1 && facl_set(fd, aclp) != 0) ||
2826         acl_set(attrname, aclp) != 0) {
2827       Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2828             attrname, jcr->last_fname, be.bstrerror());
2829       Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2830             attrname, jcr->last_fname, be.bstrerror());
2831       return bxattr_exit_error;
2832    }
2833
2834    if (aclp) {
2835       acl_free(aclp);
2836    }
2837    return bxattr_exit_ok;
2838
2839 #else /* HAVE_EXTENDED_ACL */
2840    int n;
2841    aclent_t *acls = NULL;
2842    berrno be;
2843
2844    acls = aclfromtext(acl_text, &n);
2845    if (!acls) {
2846       if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
2847            acl(attrname, SETACL, n, acls) != 0) {
2848          Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2849                attrname, jcr->last_fname, be.bstrerror());
2850          Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2851                attrname, jcr->last_fname, be.bstrerror());
2852          return bxattr_exit_error;
2853       }
2854    }
2855
2856    if (acls) {
2857       free(acls);
2858    }
2859    return bxattr_exit_ok;
2860
2861 #endif /* HAVE_EXTENDED_ACL */
2862
2863 }
2864 #endif /* HAVE_ACL */
2865
2866 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
2867 {
2868    int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
2869    int used_bytes, total_bytes, cnt;
2870    char *bp, *target_attrname, *attribs;
2871    char *linked_target = NULL;
2872    char *acl_text = NULL;
2873    char *data = NULL;
2874    int32_t inum;
2875    struct stat st;
2876    struct timeval times[2];
2877    bxattr_exit_code retval = bxattr_exit_error;
2878    berrno be;
2879
2880    /*
2881     * Parse the xattr stream. First the part that is the same for all xattrs.
2882     */
2883    used_bytes = 0;
2884    total_bytes = jcr->xattr_data->content_length;
2885
2886    /*
2887     * The name of the target xattr has a leading / we are not interested
2888     * in that so skip it when decoding the string. We always start a the /
2889     * of the xattr space anyway.
2890     */
2891    target_attrname = jcr->xattr_data->content + 1;
2892    if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
2893        (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2894       goto parse_error;
2895    }
2896    attribs = ++bp;
2897
2898    /*
2899     * Open the file on which to restore the xattrs read-only.
2900     */
2901    if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
2902       Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2903             jcr->last_fname, be.bstrerror());
2904       Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2905             jcr->last_fname, be.bstrerror());
2906       goto bail_out;
2907    }
2908
2909    /*
2910     * Open the xattr naming space and make it the current working dir.
2911     */
2912    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2913       Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
2914             jcr->last_fname, be.bstrerror());
2915       Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
2916             jcr->last_fname, be.bstrerror());
2917       goto bail_out;
2918    }
2919
2920    if (fchdir(attrdirfd) < 0) {
2921       Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2922             jcr->last_fname, be.bstrerror());
2923       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2924             jcr->last_fname, attrdirfd, be.bstrerror());
2925       goto bail_out;
2926    }
2927
2928    /*
2929     * Try to open the correct xattr subdir based on the target_attrname given.
2930     * e.g. check if its a subdir attrname. Each / in the string makes us go
2931     * one level deeper.
2932     */
2933    while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2934       *bp = '\0';
2935
2936       if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2937          Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2938                target_attrname, jcr->last_fname, be.bstrerror());
2939          Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2940                target_attrname, jcr->last_fname, be.bstrerror());
2941          goto bail_out;
2942       }
2943
2944       close(filefd);
2945       filefd = fd;
2946
2947       /*
2948        * Open the xattr naming space.
2949        */
2950       if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2951          Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2952                target_attrname, jcr->last_fname, be.bstrerror());
2953          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2954                target_attrname, jcr->last_fname, be.bstrerror());
2955          goto bail_out;
2956       }
2957
2958       close(attrdirfd);
2959       attrdirfd = fd;
2960
2961       /*
2962        * Make the xattr space our current workingdir.
2963        */
2964       if (fchdir(attrdirfd) < 0) {
2965          Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2966                target_attrname, jcr->last_fname, be.bstrerror());
2967          Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2968                target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2969          goto bail_out;
2970       }
2971
2972       target_attrname = ++bp;
2973    }
2974
2975    /*
2976     * Decode the attributes from the stream.
2977     */
2978    decode_stat(attribs, &st, &inum);
2979
2980    /*
2981     * Decode the next field (acl_text).
2982     */
2983    if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2984        (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2985       goto parse_error;
2986    }
2987    acl_text = ++bp;
2988
2989    /*
2990     * Based on the filetype perform the correct action. We support most filetypes here, more
2991     * then the actual implementation on Solaris supports so some code may never get executed
2992     * due to limitations in the implementation.
2993     */
2994    switch (st.st_mode & S_IFMT) {
2995    case S_IFIFO:
2996       /*
2997        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2998        */
2999       unlinkat(attrdirfd, target_attrname, 0);
3000       if (mkfifo(target_attrname, st.st_mode) < 0) {
3001          Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3002                target_attrname, jcr->last_fname, be.bstrerror());
3003          Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
3004                target_attrname,  jcr->last_fname, be.bstrerror());
3005          goto bail_out;
3006       }
3007       break;
3008    case S_IFCHR:
3009    case S_IFBLK:
3010       /*
3011        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3012        */
3013       unlinkat(attrdirfd, target_attrname, 0);
3014       if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3015          Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3016                target_attrname, jcr->last_fname, be.bstrerror());
3017          Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3018                target_attrname,  jcr->last_fname, be.bstrerror());
3019          goto bail_out;
3020       }
3021       break;
3022    case S_IFDIR:
3023       /*
3024        * If its not the hidden_dir create the entry.
3025        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3026        */
3027       if (!bstrcmp(target_attrname, ".")) {
3028          unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3029          if (mkdir(target_attrname, st.st_mode) < 0) {
3030             Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3031                target_attrname, jcr->last_fname, be.bstrerror());
3032             Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3033                target_attrname,  jcr->last_fname, be.bstrerror());
3034             goto bail_out;
3035          }
3036       }
3037       break;
3038    case S_IFREG:
3039       /*
3040        * See if this is a hard linked file. e.g. inum != 0
3041        */
3042       if (inum != 0) {
3043          linked_target = bp;
3044
3045          unlinkat(attrdirfd, target_attrname, 0);
3046          if (link(linked_target, target_attrname) < 0) {
3047             Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3048                   target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3049             Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3050                   target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3051             goto bail_out;
3052          }
3053
3054          /*
3055           * Successfully restored xattr.
3056           */
3057          retval = bxattr_exit_ok;
3058          goto bail_out;
3059       } else {
3060          if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3061              (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
3062             goto parse_error;
3063          }
3064
3065          if (used_bytes < (total_bytes - 1))
3066             data = ++bp;
3067
3068          /*
3069           * Restore the actual xattr.
3070           */
3071          if (!is_extensible) {
3072             unlinkat(attrdirfd, target_attrname, 0);
3073          }
3074
3075          if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3076             Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3077                   target_attrname, jcr->last_fname, be.bstrerror());
3078             Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3079                   target_attrname, jcr->last_fname, be.bstrerror());
3080             goto bail_out;
3081          }
3082       }
3083
3084       /*
3085        * Restore the actual data.
3086        */
3087       if (st.st_size > 0) {
3088          used_bytes = (data - jcr->xattr_data->content);
3089          cnt = total_bytes - used_bytes;
3090
3091          /*
3092           * Do a sanity check, the st.st_size should be the same as the number of bytes
3093           * we have available as data of the stream.
3094           */
3095          if (cnt != st.st_size) {
3096             Mmsg2(jcr->errmsg, _("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             Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3099                   target_attrname, jcr->last_fname);
3100             goto bail_out;
3101          }
3102
3103          while (cnt > 0) {
3104             cnt = write(attrfd, data, cnt);
3105             if (cnt < 0) {
3106                Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3107                      target_attrname, jcr->last_fname, be.bstrerror());
3108                Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3109                      target_attrname, jcr->last_fname, be.bstrerror());
3110                goto bail_out;
3111             }
3112
3113             used_bytes += cnt;
3114             data += cnt;
3115             cnt = total_bytes - used_bytes;
3116          }
3117       }
3118       break;
3119    case S_IFLNK:
3120       /*
3121        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3122        */
3123       linked_target = bp;
3124
3125       if (symlink(linked_target, target_attrname) < 0) {
3126          Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3127                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3128          Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3129                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3130          goto bail_out;
3131       }
3132
3133       /*
3134        * Successfully restored xattr.
3135        */
3136       retval = bxattr_exit_ok;
3137       goto bail_out;
3138    default:
3139       goto bail_out;
3140    }
3141
3142    /*
3143     * Restore owner and acl for non extensible attributes.
3144     */
3145    if (!is_extensible) {
3146       if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3147          switch (errno) {
3148          case EINVAL:
3149             /*
3150              * Gentile way of the system saying this type of xattr layering is not supported.
3151              * But as this is not an error we return a positive return value.
3152              */
3153             retval = bxattr_exit_ok;
3154             break;
3155          case ENOENT:
3156             retval = bxattr_exit_ok;
3157             break;
3158          default:
3159             Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3160                   target_attrname, jcr->last_fname, be.bstrerror());
3161             Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3162                   target_attrname, jcr->last_fname, be.bstrerror());
3163          }
3164          goto bail_out;
3165       }
3166    }
3167
3168 #ifdef HAVE_ACL
3169    if (acl_text && *acl_text)
3170       if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3171          goto bail_out;
3172 #endif /* HAVE_ACL */
3173
3174    /*
3175     * For a non extensible attribute restore access and modification time on the xattr.
3176     */
3177    if (!is_extensible) {
3178       times[0].tv_sec = st.st_atime;
3179       times[0].tv_usec = 0;
3180       times[1].tv_sec = st.st_mtime;
3181       times[1].tv_usec = 0;
3182
3183       if (futimesat(attrdirfd, target_attrname, times) < 0) {
3184          Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3185                target_attrname, jcr->last_fname, be.bstrerror());
3186          Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3187                target_attrname, jcr->last_fname, be.bstrerror());
3188          goto bail_out;
3189       }
3190    }
3191
3192    /*
3193     * Successfully restored xattr.
3194     */
3195    retval = bxattr_exit_ok;
3196    goto bail_out;
3197
3198 parse_error:
3199    Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3200          jcr->last_fname);
3201    Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3202          jcr->last_fname);
3203
3204 bail_out:
3205    if (attrfd != -1) {
3206       close(attrfd);
3207    }
3208    if (attrdirfd != -1) {
3209       close(attrdirfd);
3210    }
3211    if (filefd != -1) {
3212       close(filefd);
3213    }
3214    return retval;
3215 }
3216
3217 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3218 {
3219    char cwd[PATH_MAX];
3220    bxattr_exit_code retval = bxattr_exit_ok;
3221
3222    /*
3223     * First see if extended attributes or extensible attributes are present.
3224     * If not just pretend things went ok.
3225     */
3226    if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3227       jcr->xattr_data->nr_saved = 0;
3228       jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
3229
3230       /*
3231        * As we change the cwd in the save function save the current cwd
3232        * for restore after return from the solaris_save_xattrs function.
3233        */
3234       getcwd(cwd, sizeof(cwd));
3235       retval = solaris_save_xattrs(jcr, NULL, NULL);
3236       chdir(cwd);
3237       delete jcr->xattr_data->link_cache;
3238       jcr->xattr_data->link_cache = NULL;
3239    }
3240    return retval;
3241 }
3242
3243 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
3244 {
3245    char cwd[PATH_MAX];
3246    bool is_extensible = false;
3247    bxattr_exit_code retval;
3248
3249    /*
3250     * First make sure we can restore xattr on the filesystem.
3251     */
3252    switch (stream) {
3253 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3254    case STREAM_XATTR_SOLARIS_SYS:
3255       if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3256          Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
3257          Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3258             jcr->last_fname);
3259          return bxattr_exit_error;
3260       }
3261
3262       is_extensible = true;
3263       break;
3264 #endif
3265    case STREAM_XATTR_SOLARIS:
3266       if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3267          Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
3268          Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3269             jcr->last_fname);
3270          return bxattr_exit_error;
3271       }
3272       break;
3273    default:
3274       return bxattr_exit_error;
3275    }
3276
3277    /*
3278     * As we change the cwd in the restore function save the current cwd
3279     * for restore after return from the solaris_restore_xattrs function.
3280     */
3281    getcwd(cwd, sizeof(cwd));
3282    retval = solaris_restore_xattrs(jcr, is_extensible);
3283    chdir(cwd);
3284    return retval;
3285 }
3286
3287
3288 /*
3289  * Function pointers to the build and parse function to use for these xattrs.
3290  */
3291 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
3292 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
3293
3294 #endif /* defined(HAVE_SUN_OS) */
3295
3296 /*
3297  * Entry points when compiled with support for XATTRs on a supported platform.
3298  */
3299 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3300 {
3301    if (os_build_xattr_streams) {
3302       return (*os_build_xattr_streams)(jcr, ff_pkt);
3303    }
3304    return bxattr_exit_error;
3305 }
3306
3307 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
3308 {
3309    unsigned int cnt;
3310
3311    if (os_parse_xattr_streams) {
3312       /*
3313        * See if we can parse this stream, and ifso give it a try.
3314        */
3315       for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3316          if (os_default_xattr_streams[cnt] == stream) {
3317             return (*os_parse_xattr_streams)(jcr, stream);
3318          }
3319       }
3320    }
3321    /*
3322     * Issue a warning and discard the message. But pretend the restore was ok.
3323     */
3324    Jmsg2(jcr, M_WARNING, 0,
3325       _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3326       jcr->last_fname, stream);
3327    return bxattr_exit_error;
3328 }
3329 #endif