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