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