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