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