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