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