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