]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/xattr.c
Add comment on OpenBSD not supporting the extattr functions (anymore ?)
[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) {
542       free(xattr_list);
543    }
544    if (xattr_value_list) {
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[1] = { 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, 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        * First get the length of the available list with extended attributes.
667        */
668       xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
669       if (xattr_list_len < 0) {
670          switch (errno) {
671          case ENOENT:
672             retval = bxattr_exit_ok;
673             goto bail_out;
674          default:
675             Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
676                   jcr->last_fname, be.bstrerror());
677             Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
678                   jcr->last_fname, be.bstrerror());
679             goto bail_out;
680          }
681       } else if (xattr_list_len == 0) {
682          continue;
683       }
684
685       /*
686        * Allocate room for the extented attribute list.
687        */
688       xattr_list = (char *)malloc(xattr_list_len + 1);
689       memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
690
691       /*
692        * Get the actual list of extended attributes names for a file.
693        */
694       xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
695       if (xattr_list_len < 0) {
696          switch (errno) {
697          case ENOENT:
698             retval = bxattr_exit_ok;
699             goto bail_out;
700          default:
701             Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
702                   jcr->last_fname, be.bstrerror());
703             Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
704                   jcr->last_fname, be.bstrerror());
705             goto bail_out;
706          }
707       }
708       xattr_list[xattr_list_len] = '\0';
709
710       /*
711        * Walk the list of extended attributes names and retrieve the data.
712        * We already count the bytes needed for serializing the stream later on.
713        */
714       for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
715          skip_xattr = false;
716
717          /*
718           * print the current name into the buffer as its not null terminated we need to
719           * use the length encoded in the string for copying only the needed bytes.
720           */
721          bsnprintf(current_attrname, sizeof(current_attrname), "%*.*s",
722                    xattr_list[index], xattr_list[index], xattr_list + (index + 1));
723
724          /*
725           * First make a xattr tuple of the current namespace and the name of the xattr.
726           * e.g. something like user.<attrname> or system.<attrname>
727           */
728          if (extattr_namespace_to_string(attrnamespace, &current_attrnamespace) != 0) {
729             Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
730                   attrnamespace, jcr->last_fname);
731             Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
732                   attrnamespace, jcr->last_fname);
733             goto bail_out;
734          }
735
736          /*
737           * Create a tupple of the current attrnamespace and attrname.
738           */
739          bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
740
741          /*
742           * On some OSes you also get the acls in the extented attribute list.
743           * So we check if we are already backing up acls and if we do we
744           * don't store the extended attribute with the same info.
745           */
746          if (ff_pkt->flags & FO_ACL) {
747             for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
748                if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
749                   skip_xattr = true;
750                   break;
751                }
752             }
753          }
754
755          /*
756           * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
757           */
758          if (skip_xattr) {
759             for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
760                if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
761                   skip_xattr = true;
762                   break;
763                }
764             }
765          }
766
767          if (skip_xattr) {
768             continue;
769          }
770
771          /*
772           * Each xattr valuepair starts with a magic so we can parse it easier.
773           */
774          current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
775          current_xattr->magic = XATTR_MAGIC;
776          expected_serialize_len += sizeof(current_xattr->magic);
777
778          /*
779           * Allocate space for storing the name.
780           */
781          current_xattr->name_length = strlen(current_attrtuple);
782          current_xattr->name = (char *)malloc(current_xattr->name_length);
783          memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
784
785          expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
786
787          /*
788           * First see how long the value is for the extended attribute.
789           */
790          xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
791          if (xattr_value_len < 0) {
792             switch (errno) {
793             case ENOENT:
794                retval = bxattr_exit_ok;
795                free(current_xattr->name);
796                free(current_xattr);
797                goto bail_out;
798             default:
799                Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
800                      jcr->last_fname, be.bstrerror());
801                Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
802                      jcr->last_fname, be.bstrerror());
803                free(current_xattr->name);
804                free(current_xattr);
805                goto bail_out;
806             }
807          }
808
809          /*
810           * Allocate space for storing the value.
811           */
812          current_xattr->value = (char *)malloc(xattr_value_len);
813          memset((caddr_t)current_xattr->value, 0, xattr_value_len);
814
815          xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
816          if (xattr_value_len < 0) {
817             switch (errno) {
818             case ENOENT:
819                retval = bxattr_exit_ok;
820                free(current_xattr->value);
821                free(current_xattr->name);
822                free(current_xattr);
823                goto bail_out;
824             default:
825                Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
826                      jcr->last_fname, be.bstrerror());
827                Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
828                      jcr->last_fname, be.bstrerror());
829                free(current_xattr->value);
830                free(current_xattr->name);
831                free(current_xattr);
832                goto bail_out;
833             }
834          }
835
836          /*
837           * Store the actual length of the value.
838           */
839          current_xattr->value_length = xattr_value_len;
840          expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
841
842          /*
843           * Protect ourself against things getting out of hand.
844           */
845          if (expected_serialize_len >= MAX_XATTR_STREAM) {
846             Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
847                   jcr->last_fname, MAX_XATTR_STREAM);
848             free(current_xattr->value);
849             free(current_xattr->name);
850             free(current_xattr);
851             goto bail_out;
852          }
853
854          xattr_value_list->append(current_xattr);
855          xattr_count++;
856       }
857
858       /*
859        * We are done with this xattr list.
860        */
861       free(xattr_list);
862       xattr_list = (char *)NULL;
863    }
864
865    /*
866     * If we found any xattr send them to the SD.
867     */
868    if (xattr_count > 0) {
869       /*
870        * Serialize the datastream.
871        */
872       if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
873          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
874                jcr->last_fname);
875          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
876                jcr->last_fname);
877          goto bail_out;
878       }
879
880       xattr_drop_internal_table(xattr_value_list);
881       xattr_value_list = NULL;
882
883       /*
884        * Send the datastream to the SD.
885        */
886       return send_xattr_stream(jcr, os_default_xattr_streams[0]);
887    } else {
888       xattr_drop_internal_table(xattr_value_list);
889       xattr_value_list = NULL;
890
891       return bxattr_exit_ok;
892    }
893
894 bail_out:
895    if (xattr_list) {
896       free(xattr_list);
897    }
898    if (xattr_value_list) {
899       xattr_drop_internal_table(xattr_value_list);
900       xattr_value_list = NULL;
901    }
902    return retval;
903 }
904
905 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
906 {
907    xattr_t *current_xattr;
908    alist *xattr_value_list;
909    int current_attrnamespace, cnt;
910    char *attrnamespace, *attrname;
911    berrno be;
912
913    xattr_value_list = New(alist(10, not_owned_by_alist));
914
915    if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
916       xattr_drop_internal_table(xattr_value_list);
917       return bxattr_exit_error;
918    }
919
920    foreach_alist(current_xattr, xattr_value_list) {
921       /*
922        * Try splitting the xattr_name into a namespace and name part.
923        * The splitting character is a .
924        */
925       attrnamespace = current_xattr->name;
926       if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
927          Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
928                current_xattr->name, jcr->last_fname);
929          Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
930                current_xattr->name, jcr->last_fname);
931          goto bail_out;
932       }
933       *attrname++ = '\0';
934
935       /*
936        * Make sure the attrnamespace makes sense.
937        */
938       if (extattr_string_to_namespace(attrnamespace, &current_attrnamespace) != 0) {
939          Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
940                attrnamespace, jcr->last_fname);
941          Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
942                attrnamespace, jcr->last_fname);
943          goto bail_out;
944       }
945
946       /*
947        * Try restoring the extended attribute.
948        */
949       cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
950                              attrname, current_xattr->value, current_xattr->value_length);
951       if (cnt < 0 || cnt != current_xattr->value_length) {
952          switch (errno) {
953          case ENOENT:
954             goto bail_out;
955             break;
956          default:
957             Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
958                   jcr->last_fname, be.bstrerror());
959             Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
960                   jcr->last_fname, be.bstrerror());
961             goto bail_out;
962             break;
963          }
964       }
965    }
966
967    xattr_drop_internal_table(xattr_value_list);
968    return bxattr_exit_ok;
969
970 bail_out:
971    xattr_drop_internal_table(xattr_value_list);
972    return bxattr_exit_error;
973 }
974
975 /*
976  * Function pointers to the build and parse function to use for these xattrs.
977  */
978 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
979 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
980
981 #elif defined(HAVE_SUN_OS)
982 /*
983  * Solaris extended attributes were introduced in Solaris 9
984  * by PSARC 1999/209
985  *
986  * Solaris extensible attributes were introduced in OpenSolaris
987  * by PSARC 2007/315 Solaris extensible attributes are also
988  * sometimes called extended system attributes.
989  *
990  * man fsattr(5) on Solaris gives a wealth of info. The most
991  * important bits are:
992  *
993  * Attributes are logically supported as files within the  file
994  * system.   The  file  system  is  therefore augmented with an
995  * orthogonal name space of file attributes. Any file  (includ-
996  * ing  attribute files) can have an arbitrarily deep attribute
997  * tree associated with it. Attribute values  are  accessed  by
998  * file descriptors obtained through a special attribute inter-
999  * face.  This logical view of "attributes as files" allows the
1000  * leveraging  of  existing file system interface functionality
1001  * to support the construction, deletion, and  manipulation  of
1002  * attributes.
1003  *
1004  * The special files  "."  and  ".."  retain  their  accustomed
1005  * semantics within the attribute hierarchy.  The "." attribute
1006  * file refers to the current directory and the ".."  attribute
1007  * file  refers to the parent directory.  The unnamed directory
1008  * at the head of each attribute tree is considered the "child"
1009  * of  the  file it is associated with and the ".." file refers
1010  * to the associated file.  For  any  non-directory  file  with
1011  * attributes,  the  ".." entry in the unnamed directory refers
1012  * to a file that is not a directory.
1013  *
1014  * Conceptually, the attribute model is fully general. Extended
1015  * attributes  can  be  any  type of file (doors, links, direc-
1016  * tories, and so forth) and can even have their own attributes
1017  * (fully  recursive).   As a result, the attributes associated
1018  * with a file could be an arbitrarily deep directory hierarchy
1019  * where each attribute could have an equally complex attribute
1020  * tree associated with it.  Not all implementations  are  able
1021  * to,  or  want to, support the full model. Implementation are
1022  * therefore permitted to reject operations that are  not  sup-
1023  * ported.   For  example,  the implementation for the UFS file
1024  * system allows only regular files as attributes (for example,
1025  * no sub-directories) and rejects attempts to place attributes
1026  * on attributes.
1027  *
1028  * The following list details the operations that are  rejected
1029  * in the current implementation:
1030  *
1031  * link                     Any attempt to create links between
1032  *                          attribute  and  non-attribute space
1033  *                          is rejected  to  prevent  security-
1034  *                          related   or   otherwise  sensitive
1035  *                          attributes from being exposed,  and
1036  *                          therefore  manipulable,  as regular
1037  *                          files.
1038  *
1039  * rename                   Any  attempt  to   rename   between
1040  *                          attribute  and  non-attribute space
1041  *                          is rejected to prevent  an  already
1042  *                          linked  file from being renamed and
1043  *                          thereby circumventing the link res-
1044  *                          triction above.
1045  *
1046  * mkdir, symlink, mknod    Any  attempt  to  create  a   "non-
1047  *                          regular" file in attribute space is
1048  *                          rejected to reduce the  functional-
1049  *                          ity,  and  therefore  exposure  and
1050  *                          risk, of  the  initial  implementa-
1051  *                          tion.
1052  *
1053  * The entire available name space has been allocated to  "gen-
1054  * eral use" to bring the implementation in line with the NFSv4
1055  * draft standard [NFSv4]. That standard defines "named  attri-
1056  * butes"  (equivalent  to Solaris Extended Attributes) with no
1057  * naming restrictions.  All Sun  applications  making  use  of
1058  * opaque extended attributes will use the prefix "SUNW".
1059  *
1060  */
1061 #ifdef HAVE_SYS_ATTR_H
1062 #include <sys/attr.h>
1063 #endif
1064
1065 #ifdef HAVE_ATTR_H
1066 #include <attr.h>
1067 #endif
1068
1069 #ifdef HAVE_SYS_NVPAIR_H
1070 #include <sys/nvpair.h>
1071 #endif
1072
1073 #ifdef HAVE_SYS_ACL_H
1074 #include <sys/acl.h>
1075 #endif
1076
1077 #if !defined(HAVE_OPENAT) ||
1078     !defined(HAVE_UNKINKAT) ||
1079     !defined(HAVE_FCHOWNAT) ||
1080     !defined(HAVE_FUTIMESAT)
1081 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
1082 #endif
1083
1084 /*
1085  * Define the supported XATTR streams for this OS
1086  */
1087 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1088 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
1089 #else
1090 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
1091 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
1092
1093 /*
1094  * This code creates a temporary cache with entries for each xattr which has
1095  * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
1096  */
1097 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
1098 {
1099    xattr_link_cache_entry_t *ptr;
1100
1101    foreach_alist(ptr, jcr->xattr_data->link_cache) {
1102       if (ptr && ptr->inum == inum) {
1103          return ptr;
1104       }
1105    }
1106    return NULL;
1107 }
1108
1109 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
1110 {
1111    xattr_link_cache_entry_t *ptr;
1112
1113    ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
1114    memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
1115    ptr->inum = inum;
1116    bstrncpy(ptr->target, target, sizeof(ptr->target));
1117    jcr->xattr_data->link_cache->append(ptr);
1118 }
1119
1120 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1121 /*
1122  * This function returns true if a non default extended system attribute
1123  * list is associated with fd and returns false when an error has occured
1124  * or when only extended system attributes other than archive,
1125  * av_modified or crtime are set.
1126  *
1127  * The function returns true for the following cases:
1128  *
1129  * - any extended system attribute other than the default attributes
1130  *   ('archive', 'av_modified' and 'crtime') is set
1131  * - nvlist has NULL name string
1132  * - nvpair has data type of 'nvlist'
1133  * - default data type.
1134  */
1135 static bool solaris_has_non_transient_extensible_attributes(int fd)
1136 {
1137    boolean_t value;
1138    data_type_t type;
1139    nvlist_t *response;
1140    nvpair_t *pair;
1141    f_attr_t fattr;
1142    char *name;
1143    bool retval = false;
1144
1145    if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
1146       return false;
1147    }
1148
1149    pair = NULL;
1150    while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
1151       name = nvpair_name(pair);
1152
1153       if (name != NULL) {
1154          fattr = name_to_attr(name);
1155       } else {
1156          retval = true;
1157          goto bail_out;
1158       }
1159
1160       type = nvpair_type(pair);
1161       switch (type) {
1162       case DATA_TYPE_BOOLEAN_VALUE:
1163          if (nvpair_value_boolean_value(pair, &value) != 0) {
1164             continue;
1165          }
1166          if (value && fattr != F_ARCHIVE &&
1167                       fattr != F_AV_MODIFIED) {
1168             retval = true;
1169             goto bail_out;
1170          }
1171          break;
1172       case DATA_TYPE_UINT64_ARRAY:
1173          if (fattr != F_CRTIME) {
1174             retval = true;
1175             goto bail_out;
1176          }
1177          break;
1178       case DATA_TYPE_NVLIST:
1179       default:
1180          retval = true;
1181          goto bail_out;
1182       }
1183    }
1184
1185 bail_out:
1186    if (response != NULL) {
1187       nvlist_free(response);
1188    }
1189    return retval;
1190 }
1191 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1192
1193 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
1194 /*
1195  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1196  * There is no need to store those acls as we already store the stat bits too.
1197  */
1198 static bool acl_is_trivial(int count, aclent_t *entries)
1199 {
1200    int n;
1201    aclent_t *ace;
1202
1203    for (n = 0; n < count; n++) {
1204       ace = &entries[n];
1205       if (!(ace->a_type == USER_OBJ ||
1206             ace->a_type == GROUP_OBJ ||
1207             ace->a_type == OTHER_OBJ ||
1208             ace->a_type == CLASS_OBJ))
1209         return false;
1210    }
1211    return true;
1212 }
1213 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
1214
1215 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
1216 {
1217 #ifdef HAVE_ACL
1218 #ifdef HAVE_EXTENDED_ACL
1219    int flags;
1220    acl_t *aclp = NULL;
1221    berrno be;
1222
1223    /*
1224     * See if this attribute has an ACL
1225     */
1226    if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
1227        pathconf(attrname, _PC_ACL_ENABLED) > 0) {
1228       /*
1229        * See if there is a non trivial acl on the file.
1230        */
1231       if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
1232            acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
1233          switch (errno) {
1234          case ENOENT:
1235             return bxattr_exit_ok;
1236          default:
1237             Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1238                   attrname, jcr->last_fname, be.bstrerror());
1239             Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
1240                   attrname, jcr->last_fname, be.bstrerror());
1241             return bxattr_exit_error;
1242          }
1243       }
1244
1245       if (aclp != NULL) {
1246 #if defined(ACL_SID_FMT)
1247          /*
1248           * New format flag added in newer Solaris versions.
1249           */
1250          flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1251 #else
1252          flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1253 #endif /* ACL_SID_FMT */
1254
1255          *acl_text = acl_totext(aclp, flags);
1256          acl_free(aclp);
1257       } else {
1258          *acl_text = NULL;
1259       }
1260    } else {
1261       *acl_text = NULL;
1262    }
1263    return bxattr_exit_ok;
1264 #else /* HAVE_EXTENDED_ACL */
1265    int n;
1266    aclent_t *acls = NULL;
1267    berrno be;
1268
1269    /*
1270     * See if this attribute has an ACL
1271     */
1272    if (fd != -1) {
1273       n = facl(fd, GETACLCNT, 0, NULL);
1274    } else {
1275       n = acl(attrname, GETACLCNT, 0, NULL);
1276    }
1277
1278    if (n >= MIN_ACL_ENTRIES) {
1279       acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1280       if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
1281           acl(attrname, GETACL, n, acls) != n) {
1282          switch (errno) {
1283          case ENOENT:
1284             free(acls);
1285             return bxattr_exit_ok;
1286          default:
1287             Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1288                   attrname, jcr->last_fname, be.bstrerror());
1289             Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
1290                   attrname, jcr->last_fname, be.bstrerror());
1291             free(acls);
1292             return bxattr_exit_error;
1293          }
1294       }
1295
1296       /*
1297        * See if there is a non trivial acl on the file.
1298        */
1299       if (!acl_is_trivial(n, acls)) {
1300          if ((*acl_text = acltotext(acls, n)) == NULL) {
1301             Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
1302                   attrname, jcr->last_fname, be.bstrerror());
1303             Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
1304                   attrname, jcr->last_fname, be.bstrerror());
1305             free(acls);
1306             return bxattr_exit_error;
1307          }
1308       } else {
1309          *acl_text = NULL;
1310       }
1311
1312      free(acls);
1313    } else {
1314       *acl_text = NULL;
1315    }
1316    return bxattr_exit_ok;
1317 #endif /* HAVE_EXTENDED_ACL */
1318
1319 #else /* HAVE_ACL */
1320    return bxattr_exit_ok;
1321 #endif /* HAVE_ACL */
1322 }
1323
1324 /*
1325  * Forward declaration for recursive function call.
1326  */
1327 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
1328
1329 /*
1330  * Save an extended or extensible attribute.
1331  * This is stored as an opaque stream of bytes with the following encoding:
1332  *
1333  * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
1334  * 
1335  * or for a hardlinked or symlinked attribute
1336  *
1337  * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
1338  *
1339  * xattr_name can be a subpath relative to the file the xattr is on.
1340  * stat_buffer is the string representation of the stat struct.
1341  * acl_string is an acl text when a non trivial acl is set on the xattr.
1342  * actual_xattr_data is the content of the xattr file.
1343  */
1344 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
1345                                            const char *attrname, bool toplevel_hidden_dir, int stream)
1346 {
1347    int cnt;
1348    int attrfd = -1;
1349    struct stat st;
1350    xattr_link_cache_entry_t *xlce;
1351    char target_attrname[PATH_MAX];
1352    char link_source[PATH_MAX];
1353    char *acl_text = NULL;
1354    char attribs[MAXSTRING];
1355    char buffer[BUFSIZ];
1356    bxattr_exit_code retval = bxattr_exit_error;
1357    berrno be;
1358
1359    bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
1360
1361    /*
1362     * Get the stats of the extended or extensible attribute.
1363     */
1364    if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
1365       switch (errno) {
1366       case ENOENT:
1367          retval = bxattr_exit_ok;
1368          goto bail_out;
1369       default:
1370          Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
1371                target_attrname, jcr->last_fname, be.bstrerror());
1372          Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
1373                target_attrname, jcr->last_fname, be.bstrerror());
1374          goto bail_out;
1375       }
1376    }
1377
1378    /*
1379     * Based on the filetype perform the correct action. We support most filetypes here, more
1380     * then the actual implementation on Solaris supports so some code may never get executed
1381     * due to limitations in the implementation.
1382     */
1383    switch (st.st_mode & S_IFMT) {
1384    case S_IFIFO:
1385    case S_IFCHR:
1386    case S_IFBLK:
1387       /*
1388        * Get any acl on the xattr.
1389        */
1390       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1391          goto bail_out;
1392
1393       /*
1394        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1395        * Encode the stat struct into an ASCII representation.
1396        */
1397       encode_stat(attribs, &st, 0, stream);
1398       cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
1399                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1400       break;
1401    case S_IFDIR:
1402       /*
1403        * Get any acl on the xattr.
1404        */
1405       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1406          goto bail_out;
1407
1408       /*
1409        * See if this is the toplevel_hidden_dir being saved.
1410        */
1411       if (toplevel_hidden_dir) {
1412          /*
1413           * Save the data for later storage when we encounter a real xattr. We store the data
1414           * in the jcr->xattr_data->content buffer and flush that just before sending out the
1415           * first real xattr. Encode the stat struct into an ASCII representation and jump
1416           * out of the function.
1417           */
1418          encode_stat(attribs, &st, 0, stream);
1419          cnt = bsnprintf(buffer, sizeof(buffer),
1420                          "%s%c%s%c%s%c",
1421                          target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1422          pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1423          jcr->xattr_data->content_length = cnt;
1424          goto bail_out;
1425       } else {
1426          /*
1427           * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1428           * Encode the stat struct into an ASCII representation.
1429           */
1430          encode_stat(attribs, &st, 0, stream);
1431          cnt = bsnprintf(buffer, sizeof(buffer),
1432                          "%s%c%s%c%s%c",
1433                          target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1434       }
1435       break;
1436    case S_IFREG:
1437       /*
1438        * If this is a hardlinked file check the inode cache for a hit.
1439        */
1440       if (st.st_nlink > 1) {
1441          /*
1442           * See if the cache already knows this inode number.
1443           */
1444          if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
1445             /*
1446              * Generate a xattr encoding with the reference to the target in there.
1447              */
1448             encode_stat(attribs, &st, st.st_ino, stream);
1449             cnt = bsnprintf(buffer, sizeof(buffer),
1450                             "%s%c%s%c%s%c",
1451                             target_attrname, 0, attribs, 0, xlce->target, 0);
1452             pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1453             jcr->xattr_data->content_length = cnt;
1454             retval = send_xattr_stream(jcr, stream);
1455
1456             /*
1457              * For a hard linked file we are ready now, no need to recursively save the attributes.
1458              */
1459             goto bail_out;
1460          }
1461
1462          /*
1463           * Store this hard linked file in the cache.
1464           * Store the name relative to the top level xattr space.
1465           */
1466          add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
1467       }
1468
1469       /*
1470        * Get any acl on the xattr.
1471        */
1472       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
1473          goto bail_out;
1474       }
1475
1476       /*
1477        * Encode the stat struct into an ASCII representation.
1478        */
1479       encode_stat(attribs, &st, 0, stream);
1480       cnt = bsnprintf(buffer, sizeof(buffer),
1481                      "%s%c%s%c%s%c",
1482                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1483
1484       /*
1485        * Open the extended or extensible attribute file.
1486        */
1487       if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1488          switch (errno) {
1489          case ENOENT:
1490             retval = bxattr_exit_ok;
1491             goto bail_out;
1492          default:
1493             Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1494                   target_attrname, jcr->last_fname, be.bstrerror());
1495             Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1496                   target_attrname, jcr->last_fname, be.bstrerror());
1497             goto bail_out;
1498          }
1499       }
1500       break;
1501    case S_IFLNK:
1502       /*
1503        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1504        * Encode the stat struct into an ASCII representation.
1505        */
1506       if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1507          switch (errno) {
1508          case ENOENT:
1509             retval = bxattr_exit_ok;
1510             goto bail_out;
1511          default:
1512             Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1513                   target_attrname, jcr->last_fname, be.bstrerror());
1514             Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1515                   target_attrname, jcr->last_fname, be.bstrerror());
1516             goto bail_out;
1517          }
1518       }
1519
1520       /*
1521        * Generate a xattr encoding with the reference to the target in there.
1522        */
1523       encode_stat(attribs, &st, st.st_ino, stream);
1524       cnt = bsnprintf(buffer, sizeof(buffer),
1525                       "%s%c%s%c%s%c",
1526                       target_attrname, 0, attribs, 0, link_source, 0);
1527       pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1528       jcr->xattr_data->content_length = cnt;
1529       retval = send_xattr_stream(jcr, stream);
1530
1531       if (retval == bxattr_exit_ok) {
1532          jcr->xattr_data->nr_saved++;
1533       }
1534
1535       /*
1536        * For a soft linked file we are ready now, no need to recursively save the attributes.
1537        */
1538       goto bail_out;
1539    default:
1540       goto bail_out;
1541    }
1542
1543    /*
1544     * See if this is the first real xattr being saved.
1545     * If it is save the toplevel_hidden_dir attributes first.
1546     * This is easy as its stored already in the jcr->xattr_data->content buffer.
1547     */
1548    if (jcr->xattr_data->nr_saved == 0) {
1549       retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1550       if (retval != bxattr_exit_ok) {
1551          goto bail_out;
1552       }
1553       jcr->xattr_data->nr_saved++;
1554    }
1555
1556    pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1557    jcr->xattr_data->content_length = cnt;
1558
1559    /*
1560     * Only dump the content of regular files.
1561     */
1562    switch (st.st_mode & S_IFMT) {
1563    case S_IFREG:
1564       if (st.st_size > 0) {
1565          /*
1566           * Protect ourself against things getting out of hand.
1567           */
1568          if (st.st_size >= MAX_XATTR_STREAM) {
1569             Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1570                   jcr->last_fname, MAX_XATTR_STREAM);
1571             goto bail_out;
1572          }
1573
1574          while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1575             jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
1576             memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
1577             jcr->xattr_data->content_length += cnt;
1578          }
1579
1580          if (cnt < 0) {
1581             Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
1582                   target_attrname, jcr->last_fname);
1583             Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1584                   target_attrname, jcr->last_fname);
1585             goto bail_out;
1586          }
1587       }
1588       break;
1589
1590    default:
1591       break;
1592    }
1593
1594    if (retval) {
1595       retval = send_xattr_stream(jcr, stream);
1596       if (retval == bxattr_exit_ok) {
1597          jcr->xattr_data->nr_saved++;
1598       }
1599    }
1600
1601    /*
1602     * Recursivly call solaris_save_extended_attributes for archiving the attributes
1603     * available on this extended attribute.
1604     */
1605    if (retval) {
1606       retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1607       
1608       /*
1609        * The recursive call could change our working dir so change back to the wanted workdir.
1610        */
1611       if (fchdir(fd) < 0) {
1612          switch (errno) {
1613          case ENOENT:
1614             retval = bxattr_exit_ok;
1615             goto bail_out;
1616          default:
1617             Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1618                   jcr->last_fname, be.bstrerror());
1619             Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1620                   jcr->last_fname, fd, be.bstrerror());
1621             goto bail_out;
1622          }
1623       }
1624    }
1625
1626 bail_out:
1627    if (acl_text) {
1628       free(acl_text);
1629    }
1630    if (attrfd != -1) {
1631       close(attrfd);
1632    }
1633    return retval;
1634 }
1635
1636 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1637 {
1638    const char *name;
1639    int fd, filefd = -1, attrdirfd = -1;
1640    DIR *dirp;
1641    struct dirent *dp;
1642    char current_xattr_namespace[PATH_MAX];
1643    bxattr_exit_code retval = bxattr_exit_error;
1644    berrno be;
1645  
1646    /*
1647     * Determine what argument to use. Use attr_parent when set
1648     * (recursive call) or jcr->last_fname for first call. Also save
1649     * the current depth of the xattr_space we are in.
1650     */
1651    if (attr_parent) {
1652       name = attr_parent;
1653       if (xattr_namespace) {
1654          bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1655                    xattr_namespace, attr_parent);
1656       } else {
1657          bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1658       }
1659    } else {
1660       name = jcr->last_fname;
1661       bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1662    }
1663
1664    /*
1665     * Open the file on which to save the xattrs read-only.
1666     */
1667    if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1668       switch (errno) {
1669       case ENOENT:
1670          retval = bxattr_exit_ok;
1671          goto bail_out;
1672       default:
1673          Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1674                jcr->last_fname, be.bstrerror());
1675          Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1676                jcr->last_fname, be.bstrerror());
1677          goto bail_out;
1678       }
1679    }
1680
1681    /*
1682     * Open the xattr naming space.
1683     */
1684    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1685       switch (errno) {
1686       case EINVAL:
1687          /*
1688           * Gentile way of the system saying this type of xattr layering is not supported.
1689           * Which is not problem we just forget about this this xattr.
1690           * But as this is not an error we return a positive return value.
1691           */
1692          retval = bxattr_exit_ok;
1693          goto bail_out;
1694       case ENOENT:
1695          retval = bxattr_exit_ok;
1696          goto bail_out;
1697       default:
1698          Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1699                name, jcr->last_fname, be.bstrerror());
1700          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1701                name, jcr->last_fname, be.bstrerror());
1702          goto bail_out;
1703       }
1704    }
1705
1706   /*
1707    * We need to change into the attribute directory to determine if each of the
1708    * attributes should be saved.
1709    */
1710    if (fchdir(attrdirfd) < 0) {
1711       Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1712             jcr->last_fname, be.bstrerror());
1713       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1714             jcr->last_fname, attrdirfd, be.bstrerror());
1715       goto bail_out;
1716    }
1717
1718    /*
1719     * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1720     * else because the readdir returns "." entry after the extensible attr entry.
1721     * And as we want this entry before anything else we better just save its data.
1722     */
1723    if (!attr_parent)
1724       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1725                          true, STREAM_XATTR_SOLARIS);
1726
1727    if ((fd = dup(attrdirfd)) == -1 ||
1728        (dirp = fdopendir(fd)) == (DIR *)NULL) {
1729       Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1730             jcr->last_fname, be.bstrerror());
1731       Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1732             jcr->last_fname, fd, be.bstrerror());
1733
1734       goto bail_out;
1735    }
1736
1737    /*
1738     * Walk the namespace.
1739     */
1740    while (dp = readdir(dirp)) {
1741       /*
1742        * Skip only the toplevel . dir.
1743        */
1744       if (!attr_parent && bstrcmp(dp->d_name, "."))
1745          continue;
1746
1747       /*
1748        * Skip all .. directories
1749        */
1750       if (bstrcmp(dp->d_name, ".."))
1751          continue;
1752
1753       Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1754          current_xattr_namespace, dp->d_name, jcr->last_fname);
1755
1756 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1757       /*
1758        * We are not interested in read-only extensible attributes.
1759        */
1760       if (bstrcmp(dp->d_name, VIEW_READONLY)) {
1761          Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1762             current_xattr_namespace, dp->d_name, jcr->last_fname);
1763
1764          continue;
1765       }
1766
1767       /*
1768        * We are only interested in read-write extensible attributes
1769        * when they contain non-transient values.
1770        */
1771       if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
1772          /*
1773           * Determine if there are non-transient system attributes at the toplevel.
1774           * We need to provide a fd to the open file.
1775           */
1776          if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1777             Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1778                current_xattr_namespace, dp->d_name, jcr->last_fname);
1779             continue;
1780          }
1781
1782          /*
1783           * Save the xattr.
1784           */
1785          solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1786                             false, STREAM_XATTR_SOLARIS_SYS);
1787          continue;
1788       }
1789 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1790
1791       /*
1792        * Save the xattr.
1793        */
1794       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1795                          false, STREAM_XATTR_SOLARIS);
1796    }
1797
1798    closedir(dirp);
1799    retval = bxattr_exit_ok;
1800
1801 bail_out:
1802    if (attrdirfd != -1)
1803       close(attrdirfd);
1804    if (filefd != -1)
1805       close(filefd);
1806    return retval;
1807 }
1808
1809 #ifdef HAVE_ACL
1810 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1811 {
1812 #ifdef HAVE_EXTENDED_ACL
1813    int error;
1814    acl_t *aclp = NULL;
1815    berrno be;
1816
1817    if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1818       Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
1819             jcr->last_fname);
1820       return bxattr_exit_error;
1821    }
1822
1823    if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1824         acl_set(attrname, aclp) != 0) {
1825       Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1826             attrname, jcr->last_fname, be.bstrerror());
1827       Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1828             attrname, jcr->last_fname, be.bstrerror());
1829       return bxattr_exit_error;
1830    }
1831
1832    if (aclp) {
1833       acl_free(aclp);
1834    }
1835    return bxattr_exit_ok;
1836
1837 #else /* HAVE_EXTENDED_ACL */
1838    int n;
1839    aclent_t *acls = NULL;
1840    berrno be;
1841
1842    acls = aclfromtext(acl_text, &n);
1843    if (!acls) {
1844       if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1845            acl(attrname, SETACL, n, acls) != 0) {
1846          Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1847                attrname, jcr->last_fname, be.bstrerror());
1848          Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1849                attrname, jcr->last_fname, be.bstrerror());
1850          return bxattr_exit_error;
1851       }
1852    }
1853
1854    if (acls) {
1855       free(acls);
1856    }
1857    return bxattr_exit_ok;
1858
1859 #endif /* HAVE_EXTENDED_ACL */
1860
1861 }
1862 #endif /* HAVE_ACL */
1863
1864 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1865 {
1866    int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1867    int used_bytes, total_bytes, cnt;
1868    char *bp, *target_attrname, *attribs;
1869    char *linked_target = NULL;
1870    char *acl_text = NULL;
1871    char *data = NULL;
1872    int32_t inum;
1873    struct stat st;
1874    struct timeval times[2];
1875    bxattr_exit_code retval = bxattr_exit_error;
1876    berrno be;
1877
1878    /*
1879     * Parse the xattr stream. First the part that is the same for all xattrs.
1880     */
1881    used_bytes = 0;
1882    total_bytes = jcr->xattr_data->content_length;
1883
1884    /*
1885     * The name of the target xattr has a leading / we are not interested
1886     * in that so skip it when decoding the string. We always start a the /
1887     * of the xattr space anyway.
1888     */
1889    target_attrname = jcr->xattr_data->content + 1;
1890    if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1891        (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1892       goto parse_error;
1893    }
1894    attribs = ++bp;
1895
1896    /*
1897     * Open the file on which to restore the xattrs read-only.
1898     */
1899    if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1900       Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1901             jcr->last_fname, be.bstrerror());
1902       Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1903             jcr->last_fname, be.bstrerror());
1904       goto bail_out;
1905    }
1906
1907    /*
1908     * Open the xattr naming space and make it the current working dir.
1909     */
1910    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1911       Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1912             jcr->last_fname, be.bstrerror());
1913       Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1914             jcr->last_fname, be.bstrerror());
1915       goto bail_out;
1916    }
1917
1918    if (fchdir(attrdirfd) < 0) {
1919       Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1920             jcr->last_fname, be.bstrerror());
1921       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1922             jcr->last_fname, attrdirfd, be.bstrerror());
1923       goto bail_out;
1924    }
1925
1926    /*
1927     * Try to open the correct xattr subdir based on the target_attrname given.
1928     * e.g. check if its a subdir attrname. Each / in the string makes us go
1929     * one level deeper.
1930     */
1931    while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1932       *bp = '\0';
1933
1934       if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1935          Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1936                target_attrname, jcr->last_fname, be.bstrerror());
1937          Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1938                target_attrname, jcr->last_fname, be.bstrerror());
1939          goto bail_out;
1940       }
1941
1942       close(filefd);
1943       filefd = fd;
1944
1945       /*
1946        * Open the xattr naming space.
1947        */
1948       if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1949          Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1950                target_attrname, jcr->last_fname, be.bstrerror());
1951          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1952                target_attrname, jcr->last_fname, be.bstrerror());
1953          goto bail_out;
1954       }
1955
1956       close(attrdirfd);
1957       attrdirfd = fd;
1958
1959       /*
1960        * Make the xattr space our current workingdir.
1961        */
1962       if (fchdir(attrdirfd) < 0) {
1963          Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1964                target_attrname, jcr->last_fname, be.bstrerror());
1965          Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1966                target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1967          goto bail_out;
1968       }
1969
1970       target_attrname = ++bp;
1971    }
1972
1973    /*
1974     * Decode the attributes from the stream.
1975     */
1976    decode_stat(attribs, &st, &inum);
1977
1978    /*
1979     * Decode the next field (acl_text).
1980     */
1981    if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1982        (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1983       goto parse_error;
1984    }
1985    acl_text = ++bp;
1986
1987    /*
1988     * Based on the filetype perform the correct action. We support most filetypes here, more
1989     * then the actual implementation on Solaris supports so some code may never get executed
1990     * due to limitations in the implementation.
1991     */
1992    switch (st.st_mode & S_IFMT) {
1993    case S_IFIFO:
1994       /*
1995        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1996        */
1997       unlinkat(attrdirfd, target_attrname, 0);
1998       if (mkfifo(target_attrname, st.st_mode) < 0) {
1999          Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
2000                target_attrname, jcr->last_fname, be.bstrerror());
2001          Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
2002                target_attrname,  jcr->last_fname, be.bstrerror());
2003          goto bail_out;
2004       }
2005       break;
2006    case S_IFCHR:
2007    case S_IFBLK:
2008       /*
2009        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2010        */
2011       unlinkat(attrdirfd, target_attrname, 0);
2012       if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
2013          Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
2014                target_attrname, jcr->last_fname, be.bstrerror());
2015          Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
2016                target_attrname,  jcr->last_fname, be.bstrerror());
2017          goto bail_out;
2018       }
2019       break;
2020    case S_IFDIR:
2021       /*
2022        * If its not the hidden_dir create the entry.
2023        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2024        */
2025       if (!bstrcmp(target_attrname, ".")) {
2026          unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
2027          if (mkdir(target_attrname, st.st_mode) < 0) {
2028             Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
2029                target_attrname, jcr->last_fname, be.bstrerror());
2030             Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
2031                target_attrname,  jcr->last_fname, be.bstrerror());
2032             goto bail_out;
2033          }
2034       }
2035       break;
2036    case S_IFREG:
2037       /*
2038        * See if this is a hard linked file. e.g. inum != 0
2039        */
2040       if (inum != 0) {
2041          linked_target = bp;
2042
2043          unlinkat(attrdirfd, target_attrname, 0);
2044          if (link(linked_target, target_attrname) < 0) {
2045             Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
2046                   target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2047             Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
2048                   target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2049             goto bail_out;
2050          }
2051
2052          /*
2053           * Successfully restored xattr.
2054           */
2055          retval = bxattr_exit_ok;
2056          goto bail_out;
2057       } else {
2058          if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
2059              (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
2060             goto parse_error;
2061          }
2062
2063          if (used_bytes < (total_bytes - 1))
2064             data = ++bp;
2065
2066          /*
2067           * Restore the actual xattr.
2068           */
2069          if (!is_extensible) {
2070             unlinkat(attrdirfd, target_attrname, 0);
2071          }
2072
2073          if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
2074             Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2075                   target_attrname, jcr->last_fname, be.bstrerror());
2076             Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2077                   target_attrname, jcr->last_fname, be.bstrerror());
2078             goto bail_out;
2079          }
2080       }
2081
2082       /*
2083        * Restore the actual data.
2084        */
2085       if (st.st_size > 0) {
2086          used_bytes = (data - jcr->xattr_data->content);
2087          cnt = total_bytes - used_bytes;
2088
2089          /*
2090           * Do a sanity check, the st.st_size should be the same as the number of bytes
2091           * we have available as data of the stream.
2092           */
2093          if (cnt != st.st_size) {
2094             Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
2095                   target_attrname, jcr->last_fname);
2096             Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
2097                   target_attrname, jcr->last_fname);
2098             goto bail_out;
2099          }
2100
2101          while (cnt > 0) {
2102             cnt = write(attrfd, data, cnt);
2103             if (cnt < 0) {
2104                Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
2105                      target_attrname, jcr->last_fname, be.bstrerror());
2106                Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
2107                      target_attrname, jcr->last_fname, be.bstrerror());
2108                goto bail_out;
2109             }
2110
2111             used_bytes += cnt;
2112             data += cnt;
2113             cnt = total_bytes - used_bytes;
2114          }
2115       }
2116       break;
2117    case S_IFLNK:
2118       /*
2119        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2120        */
2121       linked_target = bp;
2122
2123       if (symlink(linked_target, target_attrname) < 0) {
2124          Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
2125                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2126          Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
2127                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2128          goto bail_out;
2129       }
2130
2131       /*
2132        * Successfully restored xattr.
2133        */
2134       retval = bxattr_exit_ok;
2135       goto bail_out;
2136    default:
2137       goto bail_out;
2138    }
2139
2140    /*
2141     * Restore owner and acl for non extensible attributes.
2142     */
2143    if (!is_extensible) {
2144       if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
2145          switch (errno) {
2146          case EINVAL:
2147             /*
2148              * Gentile way of the system saying this type of xattr layering is not supported.
2149              * But as this is not an error we return a positive return value.
2150              */
2151             retval = bxattr_exit_ok;
2152             break;
2153          case ENOENT:
2154             retval = bxattr_exit_ok;
2155             break;
2156          default:
2157             Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
2158                   target_attrname, jcr->last_fname, be.bstrerror());
2159             Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
2160                   target_attrname, jcr->last_fname, be.bstrerror());
2161          }
2162          goto bail_out;
2163       }
2164    }
2165
2166 #ifdef HAVE_ACL
2167    if (acl_text && *acl_text)
2168       if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
2169          goto bail_out;
2170 #endif /* HAVE_ACL */
2171
2172    /*
2173     * For a non extensible attribute restore access and modification time on the xattr.
2174     */
2175    if (!is_extensible) {
2176       times[0].tv_sec = st.st_atime;
2177       times[0].tv_usec = 0;
2178       times[1].tv_sec = st.st_mtime;
2179       times[1].tv_usec = 0;
2180
2181       if (futimesat(attrdirfd, target_attrname, times) < 0) {
2182          Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
2183                target_attrname, jcr->last_fname, be.bstrerror());
2184          Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
2185                target_attrname, jcr->last_fname, be.bstrerror());
2186          goto bail_out;
2187       }
2188    }
2189
2190    /*
2191     * Successfully restored xattr.
2192     */
2193    retval = bxattr_exit_ok;
2194    goto bail_out;
2195
2196 parse_error:
2197    Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
2198          jcr->last_fname);
2199    Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
2200          jcr->last_fname);
2201
2202 bail_out:
2203    if (attrfd != -1) {
2204       close(attrfd);
2205    }
2206    if (attrdirfd != -1) {
2207       close(attrdirfd);
2208    }
2209    if (filefd != -1) {
2210       close(filefd);
2211    }
2212    return retval;
2213 }
2214
2215 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2216 {
2217    char cwd[PATH_MAX];
2218    bxattr_exit_code retval = bxattr_exit_ok;
2219
2220    /*
2221     * First see if extended attributes or extensible attributes are present.
2222     * If not just pretend things went ok.
2223     */
2224    if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
2225       jcr->xattr_data->nr_saved = 0;
2226       jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
2227
2228       /*
2229        * As we change the cwd in the save function save the current cwd
2230        * for restore after return from the solaris_save_xattrs function.
2231        */
2232       getcwd(cwd, sizeof(cwd));
2233       retval = solaris_save_xattrs(jcr, NULL, NULL);
2234       chdir(cwd);
2235       delete jcr->xattr_data->link_cache;
2236       jcr->xattr_data->link_cache = NULL;
2237    }
2238    return retval;
2239 }
2240
2241 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
2242 {
2243    char cwd[PATH_MAX];
2244    bool is_extensible = false;
2245    bxattr_exit_code retval;
2246
2247    /*
2248     * First make sure we can restore xattr on the filesystem.
2249     */
2250    switch (stream) {
2251 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2252    case STREAM_XATTR_SOLARIS_SYS:
2253       if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
2254          Qmsg1(jcr, M_WARNING, 0,
2255                _("Failed to restore extensible attributes on file \"%s\"\n"),
2256                jcr->last_fname);
2257          Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
2258             jcr->last_fname);
2259          return bxattr_exit_error;
2260       }
2261
2262       is_extensible = true;
2263       break;
2264 #endif
2265    case STREAM_XATTR_SOLARIS:
2266       if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
2267          Qmsg1(jcr, M_WARNING, 0,
2268                _("Failed to restore extended attributes on file \"%s\"\n"),
2269                jcr->last_fname);
2270          Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
2271             jcr->last_fname);
2272          return bxattr_exit_error;
2273       }
2274       break;
2275    default:
2276       return bxattr_exit_error;
2277    }
2278
2279    /*
2280     * As we change the cwd in the restore function save the current cwd
2281     * for restore after return from the solaris_restore_xattrs function.
2282     */
2283    getcwd(cwd, sizeof(cwd));
2284    retval = solaris_restore_xattrs(jcr, is_extensible);
2285    chdir(cwd);
2286    return retval;
2287 }
2288
2289
2290 /*
2291  * Function pointers to the build and parse function to use for these xattrs.
2292  */
2293 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
2294 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
2295
2296 #endif /* defined(HAVE_SUN_OS) */
2297
2298 /*
2299  * Entry points when compiled with support for XATTRs on a supported platform.
2300  */
2301 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2302 {
2303    if (os_build_xattr_streams) {
2304       return (*os_build_xattr_streams)(jcr, ff_pkt);
2305    }
2306    return bxattr_exit_error;
2307 }
2308
2309 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
2310 {
2311    unsigned int cnt;
2312
2313    if (os_parse_xattr_streams) {
2314       /*
2315        * See if we can parse this stream, and ifso give it a try.
2316        */
2317       for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
2318          if (os_default_xattr_streams[cnt] == stream) {
2319             return (*os_parse_xattr_streams)(jcr, stream);
2320          }
2321       }
2322    }
2323    /*
2324     * Issue a warning and discard the message. But pretend the restore was ok.
2325     */
2326    Jmsg2(jcr, M_WARNING, 0,
2327       _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
2328       jcr->last_fname, stream);
2329    return bxattr_exit_error;
2330 }
2331 #endif