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