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