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