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