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