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