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