]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/xattr.c
Track unbalanced start/end plugin stream
[bacula/bacula] / bacula / src / filed / xattr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2008-2010 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 three of the GNU Affero 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 Affero 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  *   - AIX (Extended Attributes)
36  *   - Darwin (Extended Attributes)
37  *   - FreeBSD (Extended Attributes)
38  *   - IRIX (Extended Attributes)
39  *   - Linux (Extended Attributes)
40  *   - NetBSD (Extended Attributes)
41  *   - OpenBSD (Extended Attributes)
42  *     (As it seems either they never implemented xattr or they are removed
43  *      the support as it stated it was in version 3.1 but the current syscall
44  *      tabled shows the extattr_ functions are not implemented. So as such we
45  *      might eventually support xattr on OpenBSD when they implemented them using
46  *      the same interface as FreeBSD and NetBSD.
47  *   - Solaris (Extended Attributes and Extensible Attributes)
48  *   - Tru64 (Extended Attributes)
49  *
50  *   Written by Marco van Wieringen, November MMVIII
51  */
52
53 #include "bacula.h"
54 #include "filed.h"
55
56 #if !defined(HAVE_XATTR)
57 /**
58  * Entry points when compiled without support for XATTRs or on an unsupported platform.
59  */
60 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
61 {
62    return bxattr_exit_fatal;
63 }
64
65 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
66 {
67    return bxattr_exit_fatal;
68 }
69 #else
70 /**
71  * Send a XATTR stream to the SD.
72  */
73 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
74 {
75    BSOCK *sd = jcr->store_bsock;
76    POOLMEM *msgsave;
77 #ifdef FD_NO_SEND_TEST
78    return bxattr_exit_ok;
79 #endif
80
81    /*
82     * Sanity check
83     */
84    if (jcr->xattr_data->content_length <= 0) {
85       return bxattr_exit_ok;
86    }
87
88    /*
89     * Send header
90     */
91    if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
92       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
93             sd->bstrerror());
94       return bxattr_exit_fatal;
95    }
96
97    /*
98     * Send the buffer to the storage deamon
99     */
100    Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
101    msgsave = sd->msg;
102    sd->msg = jcr->xattr_data->content;
103    sd->msglen = jcr->xattr_data->content_length;
104    if (!sd->send()) {
105       sd->msg = msgsave;
106       sd->msglen = 0;
107       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
108             sd->bstrerror());
109       return bxattr_exit_fatal;
110    }
111
112    jcr->JobBytes += sd->msglen;
113    sd->msg = msgsave;
114    if (!sd->signal(BNET_EOD)) {
115       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
116             sd->bstrerror());
117       return bxattr_exit_fatal;
118    }
119    Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
120    return bxattr_exit_ok;
121 }
122
123 /**
124  * First some generic functions for OSes that use the same xattr encoding scheme.
125  * Currently for all OSes except for Solaris.
126  */
127 #if !defined(HAVE_SUN_OS)
128 static void xattr_drop_internal_table(alist *xattr_value_list)
129 {
130    xattr_t *current_xattr;
131
132    /*
133     * Walk the list of xattrs and free allocated memory on traversing.
134     */
135    foreach_alist(current_xattr, xattr_value_list) {
136       /*
137        * See if we can shortcut.
138        */
139       if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
140          break;
141
142       free(current_xattr->name);
143
144       if (current_xattr->value_length > 0)
145          free(current_xattr->value);
146
147       free(current_xattr);
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       if (current_xattr->value_length > 0 && current_xattr->value) {
195          ser_bytes(current_xattr->value, current_xattr->value_length);
196
197          Dmsg3(100, "Backup xattr named %s, value %*s\n",
198                current_xattr->name, current_xattr->value, current_xattr->value);
199       } else {
200          Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
201       }
202    }
203
204    ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
205    jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
206
207    return jcr->xattr_data->content_length;
208 }
209
210 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
211 {
212    unser_declare;
213    xattr_t *current_xattr;
214    bxattr_exit_code retval = bxattr_exit_ok;
215
216    /**
217     * Parse the stream and call restore_xattr_on_file for each extended attribute.
218     *
219     * Start unserializing the data. We keep on looping while we have not
220     * unserialized all bytes in the stream.
221     */
222    unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
223    while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
224       /*
225        * First make sure the magic is present. This way we can easily catch corruption.
226        * Any missing MAGIC is fatal we do NOT try to continue.
227        */
228       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
229       unser_uint32(current_xattr->magic);
230       if (current_xattr->magic != XATTR_MAGIC) {
231          Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
232                jcr->last_fname);
233          Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
234                jcr->last_fname);
235          free(current_xattr);
236          return bxattr_exit_error;
237       }
238
239       /*
240        * Decode the valuepair. First decode the length of the name.
241        */
242       unser_uint32(current_xattr->name_length);
243       if (current_xattr->name_length == 0) {
244          Mmsg1(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
245                jcr->last_fname);
246          Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
247                jcr->last_fname);
248          free(current_xattr);
249          return bxattr_exit_error;
250       }
251
252       /*
253        * Allocate room for the name and decode its content.
254        */
255       current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
256       unser_bytes(current_xattr->name, current_xattr->name_length);
257
258       /*
259        * The xattr_name needs to be null terminated.
260        */
261       current_xattr->name[current_xattr->name_length] = '\0';
262
263       /*
264        * Decode the value length.
265        */
266       unser_uint32(current_xattr->value_length);
267
268       if (current_xattr->value_length > 0) {
269          /*
270           * Allocate room for the value and decode its content.
271           */
272          current_xattr->value = (char *)malloc(current_xattr->value_length);
273          unser_bytes(current_xattr->value, current_xattr->value_length);
274
275          Dmsg3(100, "Restoring xattr named %s, value %*s\n",
276                current_xattr->name, current_xattr->value, current_xattr->value);
277       } else {
278          current_xattr->value = NULL;
279          Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
280       }
281
282       xattr_value_list->append(current_xattr);
283    }
284
285    unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
286    return retval;
287 }
288 #endif
289
290 /*
291  * This is a supported OS, See what kind of interface we should use.
292  */
293 #if defined(HAVE_AIX_OS)
294
295 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
296     (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
297     (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
298 #error "Missing full support for the Extended Attributes (EA) functions."
299 #endif
300
301 #ifdef HAVE_SYS_EA_H
302 #include <sys/ea.h>
303 #else
304 #error "Missing sys/ea.h header file"
305 #endif
306
307 /*
308  * Define the supported XATTR streams for this OS
309  */
310 static int os_default_xattr_streams[1] = { STREAM_XATTR_AIX };
311
312 /*
313  * Fallback to the non l-functions when those are not available.
314  */
315 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
316 #define lgetea getea
317 #endif
318 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
319 #define lsetea setea
320 #endif
321 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
322 #define llistea listea
323 #endif
324
325 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
326 {
327    bool skip_xattr;
328    char *xattr_list, *bp;
329    int cnt, xattr_count = 0;
330    uint32_t name_length;
331    int32_t xattr_list_len,
332            xattr_value_len;
333    uint32_t expected_serialize_len = 0;
334    xattr_t *current_xattr = NULL;
335    alist *xattr_value_list = NULL;
336    bxattr_exit_code retval = bxattr_exit_error;
337    berrno be;
338
339    /*
340     * First get the length of the available list with extended attributes.
341     */
342    xattr_list_len = llistea(jcr->last_fname, NULL, 0);
343    switch (xattr_list_len) {
344    case -1:
345       switch (errno) {
346       case ENOENT:
347       case EFORMAT:
348       case ENOTSUP:
349          return bxattr_exit_ok;
350       default:
351          Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
352                jcr->last_fname, be.bstrerror());
353          Dmsg2(100, "llistea error file=%s ERR=%s\n",
354                jcr->last_fname, be.bstrerror());
355          return bxattr_exit_error;
356       }
357       break;
358    case 0:
359       return bxattr_exit_ok;
360    default:
361       break;
362    }
363
364    /*
365     * Allocate room for the extented attribute list.
366     */
367    xattr_list = (char *)malloc(xattr_list_len + 1);
368    memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
369
370    /*
371     * Get the actual list of extended attributes names for a file.
372     */
373    xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
374    switch (xattr_list_len) {
375    case -1:
376       switch (errno) {
377       case ENOENT:
378       case EFORMAT:
379       case ENOTSUP:
380          retval = bxattr_exit_ok;
381          goto bail_out;
382       default:
383          Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
384                jcr->last_fname, be.bstrerror());
385          Dmsg2(100, "llistea error file=%s ERR=%s\n",
386                jcr->last_fname, be.bstrerror());
387          goto bail_out;
388       }
389       break;
390    default:
391       break;
392    }
393    xattr_list[xattr_list_len] = '\0';
394
395    /*
396     * Walk the list of extended attributes names and retrieve the data.
397     * We already count the bytes needed for serializing the stream later on.
398     */
399    bp = xattr_list;
400    while ((bp - xattr_list) + 1 < xattr_list_len) {
401       skip_xattr = false;
402
403       /*
404        * We want to skip certain xattrs which start with a 0xF8 character on AIX.
405        */
406       if (*bp == 0xF8) {
407          skip_xattr = true;
408       }
409
410       name_length = strlen(bp);
411       if (skip_xattr || name_length == 0) {
412          Dmsg1(100, "Skipping xattr named %s\n", bp);
413          bp = strchr(bp, '\0') + 1;
414          continue;
415       }
416
417       /*
418        * Each xattr valuepair starts with a magic so we can parse it easier.
419        */
420       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
421       current_xattr->magic = XATTR_MAGIC;
422       expected_serialize_len += sizeof(current_xattr->magic);
423
424       /*
425        * Allocate space for storing the name.
426        */
427       current_xattr->name_length = name_length;
428       current_xattr->name = (char *)malloc(current_xattr->name_length);
429       memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
430
431       expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
432
433       /*
434        * First see how long the value is for the extended attribute.
435        */
436       xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
437       switch (xattr_value_len) {
438       case -1:
439          switch (errno) {
440          case ENOENT:
441          case EFORMAT:
442          case ENOTSUP:
443             retval = bxattr_exit_ok;
444             goto bail_out;
445          default:
446             Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
447                   jcr->last_fname, be.bstrerror());
448             Dmsg2(100, "lgetea error file=%s ERR=%s\n",
449                   jcr->last_fname, be.bstrerror());
450             goto bail_out;
451          }
452          break;
453       case 0:
454          current_xattr->value = NULL;
455          current_xattr->value_length = 0;
456          expected_serialize_len += sizeof(current_xattr->value_length);
457          break;
458       default:
459          /*
460           * Allocate space for storing the value.
461           */
462          current_xattr->value = (char *)malloc(xattr_value_len);
463          memset((caddr_t)current_xattr->value, 0, xattr_value_len);
464
465          xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
466          if (xattr_value_len < 0) {
467             switch (errno) {
468             case ENOENT:
469             case EFORMAT:
470             case ENOTSUP:
471                retval = bxattr_exit_ok;
472                goto bail_out;
473             default:
474                Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
475                      jcr->last_fname, be.bstrerror());
476                Dmsg2(100, "lgetea error file=%s ERR=%s\n",
477                      jcr->last_fname, be.bstrerror());
478                goto bail_out;
479             }
480          }
481          /*
482           * Store the actual length of the value.
483           */
484          current_xattr->value_length = xattr_value_len;
485          expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
486
487          /*
488           * Protect ourself against things getting out of hand.
489           */
490          if (expected_serialize_len >= MAX_XATTR_STREAM) {
491             Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
492                   jcr->last_fname, MAX_XATTR_STREAM);
493             goto bail_out;
494          }
495       }
496
497       if (xattr_value_list == NULL) {
498          xattr_value_list = New(alist(10, not_owned_by_alist));
499       }
500
501       xattr_value_list->append(current_xattr);
502       current_xattr = NULL;
503       xattr_count++;
504       bp = strchr(bp, '\0') + 1;
505       break;
506    }
507
508    free(xattr_list);
509    xattr_list = (char *)NULL;
510
511    /*
512     * If we found any xattr send them to the SD.
513     */
514    if (xattr_count > 0) {
515       /*
516        * Serialize the datastream.
517        */
518       if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
519          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
520                jcr->last_fname);
521          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
522                jcr->last_fname);
523          goto bail_out;
524       }
525
526       /*
527        * Send the datastream to the SD.
528        */
529       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
530    } else {
531       retval = bxattr_exit_ok;
532    }
533
534 bail_out:
535    if (current_xattr != NULL) {
536       if (current_xattr->value != NULL) {
537          free(current_xattr->value);
538       }
539       if (current_xattr->name != NULL) {
540          free(current_xattr->name);
541       }
542       free(current_xattr);
543    }
544    if (xattr_list != NULL) {
545       free(xattr_list);
546    }
547    if (xattr_value_list != NULL) {
548       xattr_drop_internal_table(xattr_value_list);
549    }
550    return retval;
551 }
552
553 static bxattr_exit_code aix_xattr_parse_streams(JCR *jcr, int stream)
554 {
555    xattr_t *current_xattr;
556    alist *xattr_value_list;
557    berrno be;
558
559    xattr_value_list = New(alist(10, not_owned_by_alist));
560
561    if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
562       xattr_drop_internal_table(xattr_value_list);
563       return bxattr_exit_error;
564    }
565
566    foreach_alist(current_xattr, xattr_value_list) {
567       if (lsetea(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
568          switch (errno) {
569          case ENOENT:
570          case EFORMAT:
571          case ENOTSUP:
572             goto bail_out;
573          default:
574             Mmsg2(jcr->errmsg, _("lsetea error on file \"%s\": ERR=%s\n"),
575                   jcr->last_fname, be.bstrerror());
576             Dmsg2(100, "lsetea error file=%s ERR=%s\n",
577                   jcr->last_fname, be.bstrerror());
578             goto bail_out;
579          }
580       }
581    }
582
583    xattr_drop_internal_table(xattr_value_list);
584    return bxattr_exit_ok;
585
586 bail_out:
587    xattr_drop_internal_table(xattr_value_list);
588    return bxattr_exit_error;
589 }
590
591 /*
592  * Function pointers to the build and parse function to use for these xattrs.
593  */
594 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_xattr_build_streams;
595 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = aix_xattr_parse_streams;
596
597 #elif defined(HAVE_IRIX_OS)
598
599 /*
600  * Define the supported XATTR streams for this OS
601  */
602 static int os_default_xattr_streams[1] = { STREAM_XATTR_IRIX };
603 static const char *xattr_acl_skiplist[1] = { NULL };
604 static const char *xattr_skiplist[1] = { NULL };
605
606 struct xattr_naming_space {
607    const char *name;
608    int flags;
609 };
610
611 static xattr_naming_space xattr_naming_spaces[] = {
612    { "user.", ATTR_DONTFOLLOW },
613    { "root.", ATTR_ROOT | ATTR_DONTFOLLOW },
614    { NULL, 0 }
615 };
616
617 static bxattr_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
618 {
619    int cnt, xattr_count = 0;
620    attrlist_cursor_t cursor;
621    attrlist_t *attrlist;
622    attrlist_ent_t *attrlist_ent;
623    xattr_t *current_xattr = NULL;
624    alist *xattr_value_list = NULL;
625    uint32_t expected_serialize_len = 0;
626    bxattr_exit_code retval = bxattr_exit_error;
627    POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
628    berrno be;
629
630    for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
631       memset(cursor, 0, sizeof(attrlist_cursor_t));
632       while (1) {
633          if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
634                        xattr_naming_spaces[cnt].flags, &cursor) != 0) {
635             switch (errno) {
636             case ENOENT:
637                retval = bxattr_exit_ok;
638                goto bail_out;
639             default:
640                Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
641                      jcr->last_fname, be.bstrerror());
642                Dmsg2(100, "attr_list error file=%s ERR=%s\n",
643                      jcr->last_fname, be.bstrerror());
644                goto bail_out;
645             }
646          }
647
648          attrlist = (attrlist_t *)xattrbuf;
649
650          /*
651           * Walk the available attributes.
652           */
653          for (cnt = 0; cnt < attrlist->al_count; cnt++) {
654             attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
655
656             /*
657              * Each xattr valuepair starts with a magic so we can parse it easier.
658              */
659             current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
660             current_xattr->magic = XATTR_MAGIC;
661             expected_serialize_len += sizeof(current_xattr->magic);
662
663             /*
664              * Allocate space for storing the name.
665              * We store the name as <naming_space_name><xattr_name>
666              */
667             current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) + strlen(attrlist_ent->a_name) + 1;
668             current_xattr->name = (char *)malloc(current_xattr->name_length);
669             bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
670                       xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
671
672             expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
673
674             current_xattr->value_length = attrlist_ent->a_valuelen;
675             current_xattr->value = (char *)malloc(current_xattr->value_length);
676
677             /*
678              * Retrieve the actual value of the xattr.
679              */
680             if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
681                          current_xattr->value_length, xattr_naming_spaces[cnt].flags) != 0) {
682                switch (errno) {
683                case ENOENT:
684                case ENOATTR:
685                   retval = bxattr_exit_ok;
686                   goto bail_out;
687                case E2BIG:
688                   /*
689                    * The buffer for the xattr isn't big enough. the value of
690                    * current_xattr->value_length is updated with the actual size
691                    * of the xattr. So we free the old buffer and create a new one
692                    * and try again.
693                    */
694                   free(current_xattr->value);
695                   current_xattr->value = (char *)malloc(current_xattr->value_length);
696                   if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
697                                current_xattr->value_length, xattr_naming_spaces[cnt].flags) != 0) {
698                      switch (errno) {
699                      case ENOENT:
700                      case ENOATTR:
701                         retval = bxattr_exit_ok;
702                         goto bail_out;
703                      default:
704                         Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
705                               jcr->last_fname, be.bstrerror());
706                         Dmsg2(100, "attr_list error file=%s ERR=%s\n",
707                               jcr->last_fname, be.bstrerror());
708                         goto bail_out;
709                      }
710                   }
711                   break;
712                default:
713                   Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
714                         jcr->last_fname, be.bstrerror());
715                   Dmsg2(100, "attr_list error file=%s ERR=%s\n",
716                         jcr->last_fname, be.bstrerror());
717                   goto bail_out;
718                }
719             }
720
721             expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
722
723             /*
724              * Protect ourself against things getting out of hand.
725              */
726             if (expected_serialize_len >= MAX_XATTR_STREAM) {
727                Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
728                      jcr->last_fname, MAX_XATTR_STREAM);
729                goto bail_out;
730             }
731
732             if (xattr_value_list == NULL) {
733                xattr_value_list = New(alist(10, not_owned_by_alist));
734             }
735
736             xattr_value_list->append(current_xattr);
737             current_xattr = NULL;
738             xattr_count++;
739          }
740
741          /*
742           * See if there are more attributes available for a next run of attr_list.
743           */
744          if (attrlist->al_more == 0) {
745             break;
746          }
747       }
748    }
749
750    /*
751     * If we found any xattr send them to the SD.
752     */
753    if (xattr_count > 0) {
754       /*
755        * Serialize the datastream.
756        */
757       if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
758          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
759                jcr->last_fname);
760          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
761                jcr->last_fname);
762          goto bail_out;
763       }
764
765       /*
766        * Send the datastream to the SD.
767        */
768       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
769    } else {
770       retval = bxattr_exit_ok;
771    }
772
773 bail_out:
774    if (current_xattr != NULL) {
775       if (current_xattr->value != NULL) {
776          free(current_xattr->value);
777       }
778       if (current_xattr->name != NULL) {
779          free(current_xattr->name);
780       }
781       free(current_xattr);
782    }
783    free_pool_memory(xattrbuf);
784
785    if (xattr_value_list != NULL) {
786       xattr_drop_internal_table(xattr_value_list);
787    }
788    return retval;
789 }
790
791 static bxattr_exit_code irix_xattr_parse_streams(JCR *jcr, int stream)
792 {
793    char *bp;
794    int cnt, cmp_size, name_space_index;
795    xattr_t *current_xattr;
796    alist *xattr_value_list;
797    berrno be;
798
799    xattr_value_list = New(alist(10, not_owned_by_alist));
800
801    if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
802       xattr_drop_internal_table(xattr_value_list);
803       return bxattr_exit_error;
804    }
805
806    foreach_alist(current_xattr, xattr_value_list) {
807       /*
808        * See to what namingspace this xattr belongs to.
809        */
810       name_space_index = 0;
811       for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
812          cmp_size = strlen(xattr_naming_spaces[cnt].name);
813          if (!strncasecmp(current_xattr->name,
814                           xattr_naming_spaces[cnt].name,
815                           cmp_size)) {
816             name_space_index = cnt;
817             break;
818          }
819       }
820
821       /*
822        * If we got a xattr that doesn't belong to an valid namespace complain.
823        */
824       if (name_space_index == 0) {
825          Mmsg2(jcr->errmsg, _("Received illegal xattr named %s on file \"%s\"\n"),
826                current_xattr->name, jcr->last_fname);
827          Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
828                current_xattr->name, jcr->last_fname);
829          goto bail_out;
830       }
831
832       /*
833        * Restore the xattr first try to create the attribute from scratch.
834        */
835       flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
836       bp = strchr(current_xattr->name, '.');
837       if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
838                    current_xattr->value_len, flags) != 0) {
839          switch (errno) {
840          case ENOENT:
841             retval = bxattr_exit_ok;
842             goto bail_out;
843          case EEXIST:
844             /*
845              * The xattr already exists we need to replace it.
846              */
847             flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
848             if (attr_set(jcr->last_fname, bp, current_xattr->value,
849                          current_xattr->value_len, flags) != 0) {
850                switch (errno) {
851                case ENOENT:
852                   retval = bxattr_exit_ok;
853                   goto bail_out;
854                default:
855                   Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
856                         jcr->last_fname, be.bstrerror());
857                   Dmsg2(100, "attr_set error file=%s ERR=%s\n",
858                         jcr->last_fname, be.bstrerror());
859                   goto bail_out;
860                }
861             }
862             break;
863          default:
864             Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
865                   jcr->last_fname, be.bstrerror());
866             Dmsg2(100, "attr_set error file=%s ERR=%s\n",
867                   jcr->last_fname, be.bstrerror());
868             goto bail_out;
869          }
870       }
871    }
872
873    xattr_drop_internal_table(xattr_value_list);
874    return bxattr_exit_ok;
875
876 bail_out:
877    xattr_drop_internal_table(xattr_value_list);
878    return bxattr_exit_error;
879 }
880
881 /*
882  * Function pointers to the build and parse function to use for these xattrs.
883  */
884 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = irix_xattr_build_streams;
885 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = irix_xattr_parse_streams;
886
887 #elif defined(HAVE_DARWIN_OS) || \
888       defined(HAVE_LINUX_OS)
889
890 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
891     (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
892     (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
893 #error "Missing full support for the XATTR functions."
894 #endif
895
896 #ifdef HAVE_SYS_XATTR_H
897 #include <sys/xattr.h>
898 #else
899 #error "Missing sys/xattr.h header file"
900 #endif
901
902 /*
903  * Define the supported XATTR streams for this OS
904  */
905 #if defined(HAVE_DARWIN_OS)
906 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
907 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
908 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
909 #elif defined(HAVE_LINUX_OS)
910 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
911 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
912 static const char *xattr_skiplist[1] = { NULL };
913 #endif
914
915 /*
916  * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
917  * listxattr, getxattr and setxattr with an extra options argument
918  * which mimics the l variants of the functions when we specify
919  * XATTR_NOFOLLOW as the options value.
920  */
921 #if defined(HAVE_DARWIN_OS)
922    #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
923    #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
924    #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
925 #else
926    /*
927     * Fallback to the non l-functions when those are not available.
928     */
929    #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
930    #define lgetxattr getxattr
931    #endif
932    #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
933    #define lsetxattr setxattr
934    #endif
935    #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
936    #define llistxattr listxattr
937    #endif
938 #endif
939
940 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
941 {
942    bool skip_xattr;
943    char *xattr_list, *bp;
944    int cnt, xattr_count = 0;
945    uint32_t name_length;
946    int32_t xattr_list_len,
947            xattr_value_len;
948    uint32_t expected_serialize_len = 0;
949    xattr_t *current_xattr = NULL;
950    alist *xattr_value_list = NULL;
951    bxattr_exit_code retval = bxattr_exit_error;
952    berrno be;
953
954    /*
955     * First get the length of the available list with extended attributes.
956     */
957    xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
958    switch (xattr_list_len) {
959    case -1:
960       switch (errno) {
961       case ENOENT:
962       case ENOTSUP:
963          return bxattr_exit_ok;
964       default:
965          Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
966                jcr->last_fname, be.bstrerror());
967          Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
968                jcr->last_fname, be.bstrerror());
969          return bxattr_exit_error;
970       }
971       break;
972    case 0:
973       return bxattr_exit_ok;
974    default:
975       break;
976    }
977
978    /*
979     * Allocate room for the extented attribute list.
980     */
981    xattr_list = (char *)malloc(xattr_list_len + 1);
982    memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
983
984    /*
985     * Get the actual list of extended attributes names for a file.
986     */
987    xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
988    switch (xattr_list_len) {
989    case -1:
990       switch (errno) {
991       case ENOENT:
992       case ENOTSUP:
993          retval = bxattr_exit_ok;
994          goto bail_out;
995       default:
996          Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
997                jcr->last_fname, be.bstrerror());
998          Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
999                jcr->last_fname, be.bstrerror());
1000          goto bail_out;
1001       }
1002       break;
1003    default:
1004       break;
1005    }
1006    xattr_list[xattr_list_len] = '\0';
1007
1008    /*
1009     * Walk the list of extended attributes names and retrieve the data.
1010     * We already count the bytes needed for serializing the stream later on.
1011     */
1012    bp = xattr_list;
1013    while ((bp - xattr_list) + 1 < xattr_list_len) {
1014       skip_xattr = false;
1015
1016       /*
1017        * On some OSes you also get the acls in the extented attribute list.
1018        * So we check if we are already backing up acls and if we do we
1019        * don't store the extended attribute with the same info.
1020        */
1021       if (ff_pkt->flags & FO_ACL) {
1022          for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1023             if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1024                skip_xattr = true;
1025                break;
1026             }
1027          }
1028       }
1029
1030       /*
1031        * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1032        */
1033       if (!skip_xattr) {
1034          for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1035             if (bstrcmp(bp, xattr_skiplist[cnt])) {
1036                skip_xattr = true;
1037                break;
1038             }
1039          }
1040       }
1041
1042       name_length = strlen(bp);
1043       if (skip_xattr || name_length == 0) {
1044          Dmsg1(100, "Skipping xattr named %s\n", bp);
1045          bp = strchr(bp, '\0') + 1;
1046          continue;
1047       }
1048
1049       /*
1050        * Each xattr valuepair starts with a magic so we can parse it easier.
1051        */
1052       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1053       current_xattr->magic = XATTR_MAGIC;
1054       expected_serialize_len += sizeof(current_xattr->magic);
1055
1056       /*
1057        * Allocate space for storing the name.
1058        */
1059       current_xattr->name_length = name_length;
1060       current_xattr->name = (char *)malloc(current_xattr->name_length);
1061       memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
1062
1063       expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1064
1065       /*
1066        * First see how long the value is for the extended attribute.
1067        */
1068       xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1069       switch (xattr_value_len) {
1070       case -1:
1071          switch (errno) {
1072          case ENOENT:
1073          case ENOTSUP:
1074             retval = bxattr_exit_ok;
1075             goto bail_out;
1076          default:
1077             Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1078                   jcr->last_fname, be.bstrerror());
1079             Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1080                   jcr->last_fname, be.bstrerror());
1081             goto bail_out;
1082          }
1083          break;
1084       case 0:
1085          current_xattr->value = NULL;
1086          current_xattr->value_length = 0;
1087          expected_serialize_len += sizeof(current_xattr->value_length);
1088          break;
1089       default:
1090          /*
1091           * Allocate space for storing the value.
1092           */
1093          current_xattr->value = (char *)malloc(xattr_value_len);
1094          memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1095
1096          xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1097          if (xattr_value_len < 0) {
1098             switch (errno) {
1099             case ENOENT:
1100             case ENOTSUP:
1101                retval = bxattr_exit_ok;
1102                goto bail_out;
1103             default:
1104                Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1105                      jcr->last_fname, be.bstrerror());
1106                Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1107                      jcr->last_fname, be.bstrerror());
1108                goto bail_out;
1109             }
1110          }
1111          /*
1112           * Store the actual length of the value.
1113           */
1114          current_xattr->value_length = xattr_value_len;
1115          expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1116
1117          /*
1118           * Protect ourself against things getting out of hand.
1119           */
1120          if (expected_serialize_len >= MAX_XATTR_STREAM) {
1121             Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1122                   jcr->last_fname, MAX_XATTR_STREAM);
1123             goto bail_out;
1124          }
1125       }
1126
1127       if (xattr_value_list == NULL) {
1128          xattr_value_list = New(alist(10, not_owned_by_alist));
1129       }
1130
1131       xattr_value_list->append(current_xattr);
1132       current_xattr = NULL;
1133       xattr_count++;
1134       bp = strchr(bp, '\0') + 1;
1135       break;
1136    }
1137
1138    free(xattr_list);
1139    xattr_list = (char *)NULL;
1140
1141    /*
1142     * If we found any xattr send them to the SD.
1143     */
1144    if (xattr_count > 0) {
1145       /*
1146        * Serialize the datastream.
1147        */
1148       if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1149          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1150                jcr->last_fname);
1151          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1152                jcr->last_fname);
1153          goto bail_out;
1154       }
1155
1156       /*
1157        * Send the datastream to the SD.
1158        */
1159       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1160    } else {
1161       retval = bxattr_exit_ok;
1162    }
1163
1164 bail_out:
1165    if (current_xattr != NULL) {
1166       if (current_xattr->value != NULL) {
1167          free(current_xattr->value);
1168       }
1169       if (current_xattr->name != NULL) {
1170          free(current_xattr->name);
1171       }
1172       free(current_xattr);
1173    }
1174    if (xattr_list != NULL) {
1175       free(xattr_list);
1176    }
1177    if (xattr_value_list != NULL) {
1178       xattr_drop_internal_table(xattr_value_list);
1179    }
1180    return retval;
1181 }
1182
1183 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
1184 {
1185    xattr_t *current_xattr;
1186    alist *xattr_value_list;
1187    berrno be;
1188
1189    xattr_value_list = New(alist(10, not_owned_by_alist));
1190
1191    if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1192       xattr_drop_internal_table(xattr_value_list);
1193       return bxattr_exit_error;
1194    }
1195
1196    foreach_alist(current_xattr, xattr_value_list) {
1197       if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1198          switch (errno) {
1199          case ENOENT:
1200          case ENOTSUP:
1201             goto bail_out;
1202          default:
1203             Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
1204                   jcr->last_fname, be.bstrerror());
1205             Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1206                   jcr->last_fname, be.bstrerror());
1207             goto bail_out;
1208          }
1209       }
1210    }
1211
1212    xattr_drop_internal_table(xattr_value_list);
1213    return bxattr_exit_ok;
1214
1215 bail_out:
1216    xattr_drop_internal_table(xattr_value_list);
1217    return bxattr_exit_error;
1218 }
1219
1220 /*
1221  * Function pointers to the build and parse function to use for these xattrs.
1222  */
1223 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
1224 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
1225
1226 #elif defined(HAVE_FREEBSD_OS) || \
1227       defined(HAVE_NETBSD_OS) || \
1228       defined(HAVE_OPENBSD_OS)
1229
1230 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1231     (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1232     (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1233     !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1234     !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1235 #error "Missing full support for the extattr functions."
1236 #endif
1237
1238 #ifdef HAVE_SYS_EXTATTR_H
1239 #include <sys/extattr.h>
1240 #else
1241 #error "Missing sys/extattr.h header file"
1242 #endif
1243
1244 #ifdef HAVE_LIBUTIL_H
1245 #include <libutil.h>
1246 #endif
1247
1248 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1249 #define extattr_get_link extattr_get_file
1250 #endif
1251 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1252 #define extattr_set_link extattr_set_file
1253 #endif
1254 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1255 #define extattr_list_link extattr_list_file
1256 #endif
1257
1258 #if defined(HAVE_FREEBSD_OS)
1259 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
1260 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1261 static const char *xattr_acl_skiplist[4] = { "system.posix1e.acl_access", "system.posix1e.acl_default", "system.nfs4.acl", NULL };
1262 static const char *xattr_skiplist[1] = { NULL };
1263 #elif defined(HAVE_NETBSD_OS)
1264 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
1265 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1266 static const char *xattr_acl_skiplist[1] = { NULL };
1267 static const char *xattr_skiplist[1] = { NULL };
1268 #elif defined(HAVE_OPENBSD_OS)
1269 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
1270 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1271 static const char *xattr_acl_skiplist[1] = { NULL };
1272 static const char *xattr_skiplist[1] = { NULL };
1273 #endif
1274
1275 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1276 {
1277    bool skip_xattr;
1278    char *xattr_list;
1279    int cnt, index, xattr_count = 0;
1280    int32_t xattr_list_len,
1281            xattr_value_len;
1282    uint32_t expected_serialize_len = 0;
1283    unsigned int namespace_index;
1284    int attrnamespace;
1285    char *current_attrnamespace = NULL;
1286    char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1287    xattr_t *current_xattr = NULL;
1288    alist *xattr_value_list = NULL;
1289    bxattr_exit_code retval = bxattr_exit_error;
1290    berrno be;
1291
1292    /*
1293     * Loop over all available xattr namespaces.
1294     */
1295    for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
1296       attrnamespace = os_default_xattr_namespaces[namespace_index];
1297
1298       /*
1299        * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
1300        * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
1301        */
1302       if (extattr_namespace_to_string(attrnamespace, &current_attrnamespace) != 0) {
1303          Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
1304                attrnamespace, jcr->last_fname);
1305          Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1306                attrnamespace, jcr->last_fname);
1307          goto bail_out;
1308       }
1309
1310       /*
1311        * First get the length of the available list with extended attributes.
1312        * If we get EPERM on system namespace, don't return error.
1313        * This is expected for normal users trying to archive the system
1314        * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1315        * they've decided to return EOPNOTSUPP instead.
1316        */
1317       xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1318       switch (xattr_list_len) {
1319       case -1:
1320          switch (errno) {
1321          case ENOENT:
1322             retval = bxattr_exit_ok;
1323             goto bail_out;
1324 #if defined(EOPNOTSUPP)
1325          case EOPNOTSUPP:
1326 #endif
1327          case EPERM:
1328             if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1329                actuallyfree(current_attrnamespace);
1330                current_attrnamespace = NULL;
1331                continue;
1332             }
1333             /*
1334              * FALLTHROUGH
1335              */
1336          default:
1337             Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1338                   jcr->last_fname, be.bstrerror());
1339             Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1340                   jcr->last_fname, be.bstrerror());
1341             goto bail_out;
1342          }
1343          break;
1344       case 0:
1345          continue;
1346       default:
1347          break;
1348       }
1349
1350       /*
1351        * Allocate room for the extented attribute list.
1352        */
1353       xattr_list = (char *)malloc(xattr_list_len + 1);
1354       memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
1355
1356       /*
1357        * Get the actual list of extended attributes names for a file.
1358        */
1359       xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
1360       switch (xattr_list_len) {
1361       case -1:
1362          switch (errno) {
1363          case ENOENT:
1364             retval = bxattr_exit_ok;
1365             goto bail_out;
1366          default:
1367             Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1368                   jcr->last_fname, be.bstrerror());
1369             Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1370                   jcr->last_fname, be.bstrerror());
1371             goto bail_out;
1372          }
1373          break;
1374       default:
1375          break;
1376       }
1377       xattr_list[xattr_list_len] = '\0';
1378
1379       /*
1380        * Walk the list of extended attributes names and retrieve the data.
1381        * We already count the bytes needed for serializing the stream later on.
1382        */
1383       for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1384          skip_xattr = false;
1385
1386          /*
1387           * Print the current name into the buffer as its not null terminated we need to
1388           * use the length encoded in the string for copying only the needed bytes.
1389           */
1390          cnt = xattr_list[index];
1391          if (cnt > ((int)sizeof(current_attrname) - 1)) {
1392             cnt = ((int)sizeof(current_attrname) - 1);
1393          }
1394          strncpy(current_attrname, xattr_list + (index + 1), cnt);
1395          current_attrname[cnt] = '\0';
1396
1397          /*
1398           * First make a xattr tuple of the current namespace and the name of the xattr.
1399           * e.g. something like user.<attrname> or system.<attrname>
1400           */
1401          bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
1402
1403          /*
1404           * On some OSes you also get the acls in the extented attribute list.
1405           * So we check if we are already backing up acls and if we do we
1406           * don't store the extended attribute with the same info.
1407           */
1408          if (ff_pkt->flags & FO_ACL) {
1409             for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1410                if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1411                   skip_xattr = true;
1412                   break;
1413                }
1414             }
1415          }
1416
1417          /*
1418           * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1419           */
1420          if (!skip_xattr) {
1421             for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1422                if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1423                   skip_xattr = true;
1424                   break;
1425                }
1426             }
1427          }
1428
1429          if (skip_xattr) {
1430             Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1431             continue;
1432          }
1433
1434          /*
1435           * Each xattr valuepair starts with a magic so we can parse it easier.
1436           */
1437          current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1438          current_xattr->magic = XATTR_MAGIC;
1439          expected_serialize_len += sizeof(current_xattr->magic);
1440
1441          /*
1442           * Allocate space for storing the name.
1443           */
1444          current_xattr->name_length = strlen(current_attrtuple);
1445          current_xattr->name = (char *)malloc(current_xattr->name_length);
1446          memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
1447
1448          expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1449
1450          /*
1451           * First see how long the value is for the extended attribute.
1452           */
1453          xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
1454          switch (xattr_value_len) {
1455          case -1:
1456             switch (errno) {
1457             case ENOENT:
1458                retval = bxattr_exit_ok;
1459                goto bail_out;
1460             default:
1461                Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1462                      jcr->last_fname, be.bstrerror());
1463                Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1464                      jcr->last_fname, be.bstrerror());
1465                goto bail_out;
1466             }
1467             break;
1468          case 0:
1469             current_xattr->value = NULL;
1470             current_xattr->value_length = 0;
1471             expected_serialize_len += sizeof(current_xattr->value_length);
1472             break;
1473          default:
1474             /*
1475              * Allocate space for storing the value.
1476              */
1477             current_xattr->value = (char *)malloc(xattr_value_len);
1478             memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1479
1480             xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
1481             if (xattr_value_len < 0) {
1482                switch (errno) {
1483                case ENOENT:
1484                   retval = bxattr_exit_ok;
1485                   goto bail_out;
1486                default:
1487                   Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1488                         jcr->last_fname, be.bstrerror());
1489                   Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1490                         jcr->last_fname, be.bstrerror());
1491                   goto bail_out;
1492                }
1493             }
1494
1495             /*
1496              * Store the actual length of the value.
1497              */
1498             current_xattr->value_length = xattr_value_len;
1499             expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1500
1501             /*
1502              * Protect ourself against things getting out of hand.
1503              */
1504             if (expected_serialize_len >= MAX_XATTR_STREAM) {
1505                Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1506                      jcr->last_fname, MAX_XATTR_STREAM);
1507                goto bail_out;
1508             }
1509             break;
1510          }
1511
1512          if (xattr_value_list == NULL) {
1513             xattr_value_list = New(alist(10, not_owned_by_alist));
1514          }
1515
1516          xattr_value_list->append(current_xattr);
1517          current_xattr = NULL;
1518          xattr_count++;
1519
1520       }
1521
1522       /*
1523        * Drop the local copy of the current_attrnamespace.
1524        */
1525       actuallyfree(current_attrnamespace);
1526       current_attrnamespace = NULL;
1527
1528       /*
1529        * We are done with this xattr list.
1530        */
1531       free(xattr_list);
1532       xattr_list = (char *)NULL;
1533    }
1534
1535    /*
1536     * If we found any xattr send them to the SD.
1537     */
1538    if (xattr_count > 0) {
1539       /*
1540        * Serialize the datastream.
1541        */
1542       if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1543          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1544                jcr->last_fname);
1545          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1546                jcr->last_fname);
1547          goto bail_out;
1548       }
1549
1550       /*
1551        * Send the datastream to the SD.
1552        */
1553       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1554    } else {
1555       retval = bxattr_exit_ok;
1556    }
1557
1558 bail_out:
1559    if (current_attrnamespace != NULL) {
1560       actuallyfree(current_attrnamespace);
1561    }
1562    if (current_xattr != NULL) {
1563       if (current_xattr->value != NULL) {
1564          free(current_xattr->value);
1565       }
1566       if (current_xattr->name != NULL) {
1567          free(current_xattr->name);
1568       }
1569       free(current_xattr);
1570    }
1571    if (xattr_list != NULL) {
1572       free(xattr_list);
1573    }
1574    if (xattr_value_list != NULL) {
1575       xattr_drop_internal_table(xattr_value_list);
1576    }
1577    return retval;
1578 }
1579
1580 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
1581 {
1582    xattr_t *current_xattr;
1583    alist *xattr_value_list;
1584    int current_attrnamespace, cnt;
1585    char *attrnamespace, *attrname;
1586    berrno be;
1587
1588    xattr_value_list = New(alist(10, not_owned_by_alist));
1589
1590    if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1591       xattr_drop_internal_table(xattr_value_list);
1592       return bxattr_exit_error;
1593    }
1594
1595    foreach_alist(current_xattr, xattr_value_list) {
1596       /*
1597        * Try splitting the xattr_name into a namespace and name part.
1598        * The splitting character is a .
1599        */
1600       attrnamespace = current_xattr->name;
1601       if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1602          Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1603                current_xattr->name, jcr->last_fname);
1604          Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1605                current_xattr->name, jcr->last_fname);
1606          goto bail_out;
1607       }
1608       *attrname++ = '\0';
1609
1610       /*
1611        * Make sure the attrnamespace makes sense.
1612        */
1613       if (extattr_string_to_namespace(attrnamespace, &current_attrnamespace) != 0) {
1614          Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1615                attrnamespace, jcr->last_fname);
1616          Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1617                attrnamespace, jcr->last_fname);
1618          goto bail_out;
1619       }
1620
1621       /*
1622        * Try restoring the extended attribute.
1623        */
1624       cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1625                              attrname, current_xattr->value, current_xattr->value_length);
1626       if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1627          switch (errno) {
1628          case ENOENT:
1629             goto bail_out;
1630             break;
1631          default:
1632             Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1633                   jcr->last_fname, be.bstrerror());
1634             Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1635                   jcr->last_fname, be.bstrerror());
1636             goto bail_out;
1637             break;
1638          }
1639       }
1640    }
1641
1642    xattr_drop_internal_table(xattr_value_list);
1643    return bxattr_exit_ok;
1644
1645 bail_out:
1646    xattr_drop_internal_table(xattr_value_list);
1647    return bxattr_exit_error;
1648 }
1649
1650 /*
1651  * Function pointers to the build and parse function to use for these xattrs.
1652  */
1653 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1654 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1655
1656 #elif defined(HAVE_OSF1_OS)
1657
1658 #if !defined(HAVE_GETPROPLIST) || \
1659     !defined(HAVE_GET_PROPLIST_ENTRY) || \
1660     !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1661     !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1662     !defined(HAVE_SETPROPLIST)
1663 #error "Missing full support for the Extended Attributes functions."
1664 #endif
1665
1666 #ifdef HAVE_SYS_PROPLIST_H
1667 #include <sys/proplist.h>
1668 #else
1669 #error "Missing sys/proplist.h header file"
1670 #endif
1671
1672 /*
1673  * Define the supported XATTR streams for this OS
1674  */
1675 static int os_default_xattr_streams[1] = { STREAM_XATTR_TRU64 };
1676 static const char *xattr_acl_skiplist[1] = { NULL };
1677 static const char *xattr_skiplist[1] = { NULL };
1678
1679 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1680 {
1681    char *bp,
1682         *xattr_name,
1683         *xattr_value;
1684    bool skip_xattr;
1685    int xattr_count = 0;
1686    int32_t *flags,
1687            *xattr_value_len;
1688    int32_t xattr_list_len,
1689            xattrbuf_size,
1690            xattrbuf_min_size;
1691    uint32_t expected_serialize_len = 0;
1692    xattr_t *current_xattr = NULL;
1693    alist *xattr_value_list = NULL;
1694    struct proplistname_args prop_args;
1695    bxattr_exit_code retval = bxattr_exit_error;
1696    POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1697    berrno be;
1698
1699    xattrbuf_size = sizeof_pool_memory(xattrbuf);
1700    xattrbuf_min_size = 0;
1701    xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1702                                 xattrbuf, &xattrbuf_min_size);
1703
1704    /*
1705     * See what xattr are available.
1706     */
1707    switch (xattr_list_len) {
1708    case -1:
1709       switch (errno) {
1710       case EOPNOTSUPP:
1711          retval = bacl_exit_ok;
1712          goto bail_out;
1713       default:
1714          Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1715                jcr->last_fname, be.bstrerror());
1716          Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1717                jcr->last_fname, be.bstrerror());
1718          goto bail_out;
1719       }
1720       break;
1721    case 0:
1722       if (xattrbuf_min_size) {
1723          /*
1724           * The buffer isn't big enough to hold the xattr data, we now have
1725           * a minimum buffersize so we resize the buffer and try again.
1726           */
1727          xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1728          xattrbuf_size = xattrbuf_min_size + 1;
1729          xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1730                                    xattrbuf, &xattrbuf_min_size);
1731          switch (xattr_list_len) {
1732          case -1:
1733             switch (errno) {
1734             case EOPNOTSUPP:
1735                retval = bacl_exit_ok;
1736                goto bail_out;
1737             default:
1738                Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1739                      jcr->last_fname, be.bstrerror());
1740                Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1741                      jcr->last_fname, be.bstrerror());
1742                goto bail_out;
1743             }
1744             break;
1745          case 0:
1746             /*
1747              * This should never happen as we sized the buffer according to the minimumsize
1748              * returned by a previous getproplist call. If it does happen things are fishy and
1749              * we are better of forgetting this xattr as it seems its list is changing at this
1750              * exact moment so we can never make a good backup copy of it.
1751              */
1752             retval = bacl_exit_ok;
1753             goto bail_out;
1754          default:
1755             break;
1756          }
1757       } else {
1758          /**
1759           * No xattr on file.
1760           */
1761          retval = bacl_exit_ok;
1762          goto bail_out;
1763       }
1764       break;
1765    default:
1766       break;
1767    }
1768
1769    /*
1770     * Walk the list of extended attributes names and retrieve the data.
1771     * We already count the bytes needed for serializing the stream later on.
1772     */
1773    bp = xattrbuf;
1774    while (xattrbuf_size > 0) {
1775       /*
1776        * Call getproplist_entry to initialize name and value
1777        * pointers to entries position within buffer.
1778        */
1779       xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
1780
1781       /*
1782        * On some OSes you also get the acls in the extented attribute list.
1783        * So we check if we are already backing up acls and if we do we
1784        * don't store the extended attribute with the same info.
1785        */
1786       if (ff_pkt->flags & FO_ACL) {
1787          for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1788             if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
1789                skip_xattr = true;
1790                break;
1791             }
1792          }
1793       }
1794
1795       /*
1796        * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1797        */
1798       if (!skip_xattr) {
1799          for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1800             if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
1801                skip_xattr = true;
1802                break;
1803             }
1804          }
1805       }
1806
1807       if (skip_xattr) {
1808          Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
1809          continue;
1810       }
1811
1812       /*
1813        * Each xattr valuepair starts with a magic so we can parse it easier.
1814        */
1815       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1816       current_xattr->magic = XATTR_MAGIC;
1817       expected_serialize_len += sizeof(current_xattr->magic);
1818
1819       current_xattr->name_length = strlen(xattr_name);
1820       current_xattr->name = bstrdup(xattr_name);
1821
1822       expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1823
1824       current_xattr->value_length = *xattr_value_len;
1825       current_xattr->value = (char *)malloc(current_xattr->value_length);
1826       memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
1827
1828       expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1829
1830       /*
1831        * Protect ourself against things getting out of hand.
1832        */
1833       if (expected_serialize_len >= MAX_XATTR_STREAM) {
1834          Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1835                jcr->last_fname, MAX_XATTR_STREAM);
1836          goto bail_out;
1837       }
1838
1839       if (xattr_value_list == NULL) {
1840          xattr_value_list = New(alist(10, not_owned_by_alist));
1841       }
1842
1843       xattr_value_list->append(current_xattr);
1844       current_xattr = NULL;
1845       xattr_count++;
1846    }
1847
1848    /*
1849     * If we found any xattr send them to the SD.
1850     */
1851    if (xattr_count > 0) {
1852       /*
1853        * Serialize the datastream.
1854        */
1855       if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1856          Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1857                jcr->last_fname);
1858          Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1859                jcr->last_fname);
1860          goto bail_out;
1861       }
1862
1863       /*
1864        * Send the datastream to the SD.
1865        */
1866       retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1867    }
1868
1869 bail_out:
1870    if (current_xattr != NULL) {
1871       if (current_xattr->value != NULL) {
1872          free(current_xattr->value);
1873       }
1874       if (current_xattr->name != NULL) {
1875          free(current_xattr->name);
1876       }
1877       free(current_xattr);
1878    }
1879    if (xattr_value_list != NULL) {
1880       xattr_drop_internal_table(xattr_value_list);
1881    }
1882    free_pool_memory(xattrbuf);
1883
1884    return retval;
1885 }
1886
1887 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr, int stream)
1888 {
1889    char *bp, *xattrbuf = NULL;
1890    int32_t xattrbuf_size, cnt;
1891    xattr_t *current_xattr;
1892    alist *xattr_value_list;
1893    berrno be;
1894
1895    xattr_value_list = New(alist(10, not_owned_by_alist));
1896
1897    if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1898       xattr_drop_internal_table(xattr_value_list);
1899       return bxattr_exit_error;
1900    }
1901
1902    /*
1903     * See how big the propertylist must be.
1904     */
1905    xattrbuf_size = 0;
1906    foreach_alist(current_xattr, xattr_value_list) {
1907       xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
1908    }
1909
1910    xattrbuf = (char *)malloc(xattrbuf_size);
1911
1912    /*
1913     * Add all value pairs to the proplist.
1914     */
1915    cnt = 0;
1916    bp = xattrbuf;
1917    foreach_alist(current_xattr, xattr_value_list) {
1918       cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
1919                                current_xattr->value, &bp);
1920    }
1921
1922    /*
1923     * Sanity check.
1924     */
1925    if (cnt != xattrbuf_size) {
1926       Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
1927             jcr->last_fname);
1928       Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
1929             jcr->last_fname);
1930       goto bail_out;
1931    }
1932
1933    /*
1934     * Restore the list of extended attributes on the file.
1935     */
1936    cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
1937    switch (cnt) {
1938    case -1:
1939       switch (errno) {
1940       case EOPNOTSUPP:
1941          retval = bacl_exit_ok;
1942          goto bail_out;
1943       default:
1944          Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
1945                jcr->last_fname, be.bstrerror());
1946          Dmsg2(100, "setproplist error file=%s ERR=%s\n",
1947                jcr->last_fname, be.bstrerror());
1948          goto bail_out;
1949       }
1950       break;
1951    default:
1952       break;
1953    }
1954
1955    free(xattrbuf);
1956
1957    xattr_drop_internal_table(xattr_value_list);
1958    return bxattr_exit_ok;
1959
1960 bail_out:
1961    if (xattrbuf) {
1962       free(xattrbuf);
1963    }
1964    xattr_drop_internal_table(xattr_value_list);
1965    return bxattr_exit_error;
1966 }
1967
1968 /*
1969  * Function pointers to the build and parse function to use for these xattrs.
1970  */
1971 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_xattr_streams;
1972 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = tru64_parse_xattr_streams;
1973
1974 #elif defined(HAVE_SUN_OS)
1975 /*
1976  * Solaris extended attributes were introduced in Solaris 9
1977  * by PSARC 1999/209
1978  *
1979  * Solaris extensible attributes were introduced in OpenSolaris
1980  * by PSARC 2007/315 Solaris extensible attributes are also
1981  * sometimes called extended system attributes.
1982  *
1983  * man fsattr(5) on Solaris gives a wealth of info. The most
1984  * important bits are:
1985  *
1986  * Attributes are logically supported as files within the  file
1987  * system.   The  file  system  is  therefore augmented with an
1988  * orthogonal name space of file attributes. Any file  (includ-
1989  * ing  attribute files) can have an arbitrarily deep attribute
1990  * tree associated with it. Attribute values  are  accessed  by
1991  * file descriptors obtained through a special attribute inter-
1992  * face.  This logical view of "attributes as files" allows the
1993  * leveraging  of  existing file system interface functionality
1994  * to support the construction, deletion, and  manipulation  of
1995  * attributes.
1996  *
1997  * The special files  "."  and  ".."  retain  their  accustomed
1998  * semantics within the attribute hierarchy.  The "." attribute
1999  * file refers to the current directory and the ".."  attribute
2000  * file  refers to the parent directory.  The unnamed directory
2001  * at the head of each attribute tree is considered the "child"
2002  * of  the  file it is associated with and the ".." file refers
2003  * to the associated file.  For  any  non-directory  file  with
2004  * attributes,  the  ".." entry in the unnamed directory refers
2005  * to a file that is not a directory.
2006  *
2007  * Conceptually, the attribute model is fully general. Extended
2008  * attributes  can  be  any  type of file (doors, links, direc-
2009  * tories, and so forth) and can even have their own attributes
2010  * (fully  recursive).   As a result, the attributes associated
2011  * with a file could be an arbitrarily deep directory hierarchy
2012  * where each attribute could have an equally complex attribute
2013  * tree associated with it.  Not all implementations  are  able
2014  * to,  or  want to, support the full model. Implementation are
2015  * therefore permitted to reject operations that are  not  sup-
2016  * ported.   For  example,  the implementation for the UFS file
2017  * system allows only regular files as attributes (for example,
2018  * no sub-directories) and rejects attempts to place attributes
2019  * on attributes.
2020  *
2021  * The following list details the operations that are  rejected
2022  * in the current implementation:
2023  *
2024  * link                     Any attempt to create links between
2025  *                          attribute  and  non-attribute space
2026  *                          is rejected  to  prevent  security-
2027  *                          related   or   otherwise  sensitive
2028  *                          attributes from being exposed,  and
2029  *                          therefore  manipulable,  as regular
2030  *                          files.
2031  *
2032  * rename                   Any  attempt  to   rename   between
2033  *                          attribute  and  non-attribute space
2034  *                          is rejected to prevent  an  already
2035  *                          linked  file from being renamed and
2036  *                          thereby circumventing the link res-
2037  *                          triction above.
2038  *
2039  * mkdir, symlink, mknod    Any  attempt  to  create  a   "non-
2040  *                          regular" file in attribute space is
2041  *                          rejected to reduce the  functional-
2042  *                          ity,  and  therefore  exposure  and
2043  *                          risk, of  the  initial  implementa-
2044  *                          tion.
2045  *
2046  * The entire available name space has been allocated to  "gen-
2047  * eral use" to bring the implementation in line with the NFSv4
2048  * draft standard [NFSv4]. That standard defines "named  attri-
2049  * butes"  (equivalent  to Solaris Extended Attributes) with no
2050  * naming restrictions.  All Sun  applications  making  use  of
2051  * opaque extended attributes will use the prefix "SUNW".
2052  *
2053  */
2054 #ifdef HAVE_SYS_ATTR_H
2055 #include <sys/attr.h>
2056 #endif
2057
2058 #ifdef HAVE_ATTR_H
2059 #include <attr.h>
2060 #endif
2061
2062 #ifdef HAVE_SYS_NVPAIR_H
2063 #include <sys/nvpair.h>
2064 #endif
2065
2066 #ifdef HAVE_SYS_ACL_H
2067 #include <sys/acl.h>
2068 #endif
2069
2070 #if !defined(HAVE_OPENAT) || \
2071     !defined(HAVE_UNLINKAT) || \
2072     !defined(HAVE_FCHOWNAT) || \
2073     !defined(HAVE_FUTIMESAT)
2074 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2075 #endif
2076
2077 /*
2078  * Define the supported XATTR streams for this OS
2079  */
2080 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2081 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
2082 #else
2083 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
2084 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2085
2086 /*
2087  * This code creates a temporary cache with entries for each xattr which has
2088  * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2089  */
2090 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2091 {
2092    xattr_link_cache_entry_t *ptr;
2093
2094    foreach_alist(ptr, jcr->xattr_data->link_cache) {
2095       if (ptr && ptr->inum == inum) {
2096          return ptr;
2097       }
2098    }
2099    return NULL;
2100 }
2101
2102 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2103 {
2104    xattr_link_cache_entry_t *ptr;
2105
2106    ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2107    memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
2108    ptr->inum = inum;
2109    bstrncpy(ptr->target, target, sizeof(ptr->target));
2110    jcr->xattr_data->link_cache->append(ptr);
2111 }
2112
2113 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2114 /*
2115  * This function returns true if a non default extended system attribute
2116  * list is associated with fd and returns false when an error has occured
2117  * or when only extended system attributes other than archive,
2118  * av_modified or crtime are set.
2119  *
2120  * The function returns true for the following cases:
2121  *
2122  * - any extended system attribute other than the default attributes
2123  *   ('archive', 'av_modified' and 'crtime') is set
2124  * - nvlist has NULL name string
2125  * - nvpair has data type of 'nvlist'
2126  * - default data type.
2127  */
2128 static bool solaris_has_non_transient_extensible_attributes(int fd)
2129 {
2130    boolean_t value;
2131    data_type_t type;
2132    nvlist_t *response;
2133    nvpair_t *pair;
2134    f_attr_t fattr;
2135    char *name;
2136    bool retval = false;
2137
2138    if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2139       return false;
2140    }
2141
2142    pair = NULL;
2143    while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2144       name = nvpair_name(pair);
2145
2146       if (name != NULL) {
2147          fattr = name_to_attr(name);
2148       } else {
2149          retval = true;
2150          goto bail_out;
2151       }
2152
2153       type = nvpair_type(pair);
2154       switch (type) {
2155       case DATA_TYPE_BOOLEAN_VALUE:
2156          if (nvpair_value_boolean_value(pair, &value) != 0) {
2157             continue;
2158          }
2159          if (value && fattr != F_ARCHIVE &&
2160                       fattr != F_AV_MODIFIED) {
2161             retval = true;
2162             goto bail_out;
2163          }
2164          break;
2165       case DATA_TYPE_UINT64_ARRAY:
2166          if (fattr != F_CRTIME) {
2167             retval = true;
2168             goto bail_out;
2169          }
2170          break;
2171       case DATA_TYPE_NVLIST:
2172       default:
2173          retval = true;
2174          goto bail_out;
2175       }
2176    }
2177
2178 bail_out:
2179    if (response != NULL) {
2180       nvlist_free(response);
2181    }
2182    return retval;
2183 }
2184 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2185
2186 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2187 /*
2188  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2189  * There is no need to store those acls as we already store the stat bits too.
2190  */
2191 static bool acl_is_trivial(int count, aclent_t *entries)
2192 {
2193    int n;
2194    aclent_t *ace;
2195
2196    for (n = 0; n < count; n++) {
2197       ace = &entries[n];
2198       if (!(ace->a_type == USER_OBJ ||
2199             ace->a_type == GROUP_OBJ ||
2200             ace->a_type == OTHER_OBJ ||
2201             ace->a_type == CLASS_OBJ))
2202         return false;
2203    }
2204    return true;
2205 }
2206 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2207
2208 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2209 {
2210 #ifdef HAVE_ACL
2211 #ifdef HAVE_EXTENDED_ACL
2212    int flags;
2213    acl_t *aclp = NULL;
2214    berrno be;
2215
2216    /*
2217     * See if this attribute has an ACL
2218     */
2219    if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2220        pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2221       /*
2222        * See if there is a non trivial acl on the file.
2223        */
2224       if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2225            acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2226          switch (errno) {
2227          case ENOENT:
2228             return bxattr_exit_ok;
2229          default:
2230             Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2231                   attrname, jcr->last_fname, be.bstrerror());
2232             Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2233                   attrname, jcr->last_fname, be.bstrerror());
2234             return bxattr_exit_error;
2235          }
2236       }
2237
2238       if (aclp != NULL) {
2239 #if defined(ACL_SID_FMT)
2240          /*
2241           * New format flag added in newer Solaris versions.
2242           */
2243          flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2244 #else
2245          flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2246 #endif /* ACL_SID_FMT */
2247
2248          *acl_text = acl_totext(aclp, flags);
2249          acl_free(aclp);
2250       } else {
2251          *acl_text = NULL;
2252       }
2253    } else {
2254       *acl_text = NULL;
2255    }
2256    return bxattr_exit_ok;
2257 #else /* HAVE_EXTENDED_ACL */
2258    int n;
2259    aclent_t *acls = NULL;
2260    berrno be;
2261
2262    /*
2263     * See if this attribute has an ACL
2264     */
2265    if (fd != -1) {
2266       n = facl(fd, GETACLCNT, 0, NULL);
2267    } else {
2268       n = acl(attrname, GETACLCNT, 0, NULL);
2269    }
2270
2271    if (n >= MIN_ACL_ENTRIES) {
2272       acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2273       if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2274           acl(attrname, GETACL, n, acls) != n) {
2275          switch (errno) {
2276          case ENOENT:
2277             free(acls);
2278             return bxattr_exit_ok;
2279          default:
2280             Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2281                   attrname, jcr->last_fname, be.bstrerror());
2282             Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2283                   attrname, jcr->last_fname, be.bstrerror());
2284             free(acls);
2285             return bxattr_exit_error;
2286          }
2287       }
2288
2289       /*
2290        * See if there is a non trivial acl on the file.
2291        */
2292       if (!acl_is_trivial(n, acls)) {
2293          if ((*acl_text = acltotext(acls, n)) == NULL) {
2294             Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2295                   attrname, jcr->last_fname, be.bstrerror());
2296             Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2297                   attrname, jcr->last_fname, be.bstrerror());
2298             free(acls);
2299             return bxattr_exit_error;
2300          }
2301       } else {
2302          *acl_text = NULL;
2303       }
2304
2305      free(acls);
2306    } else {
2307       *acl_text = NULL;
2308    }
2309    return bxattr_exit_ok;
2310 #endif /* HAVE_EXTENDED_ACL */
2311
2312 #else /* HAVE_ACL */
2313    return bxattr_exit_ok;
2314 #endif /* HAVE_ACL */
2315 }
2316
2317 /*
2318  * Forward declaration for recursive function call.
2319  */
2320 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2321
2322 /*
2323  * Save an extended or extensible attribute.
2324  * This is stored as an opaque stream of bytes with the following encoding:
2325  *
2326  * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2327  * 
2328  * or for a hardlinked or symlinked attribute
2329  *
2330  * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2331  *
2332  * xattr_name can be a subpath relative to the file the xattr is on.
2333  * stat_buffer is the string representation of the stat struct.
2334  * acl_string is an acl text when a non trivial acl is set on the xattr.
2335  * actual_xattr_data is the content of the xattr file.
2336  */
2337 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2338                                            const char *attrname, bool toplevel_hidden_dir, int stream)
2339 {
2340    int cnt;
2341    int attrfd = -1;
2342    struct stat st;
2343    xattr_link_cache_entry_t *xlce;
2344    char target_attrname[PATH_MAX];
2345    char link_source[PATH_MAX];
2346    char *acl_text = NULL;
2347    char attribs[MAXSTRING];
2348    char buffer[XATTR_BUFSIZ];
2349    bxattr_exit_code retval = bxattr_exit_error;
2350    berrno be;
2351
2352    bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2353
2354    /*
2355     * Get the stats of the extended or extensible attribute.
2356     */
2357    if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2358       switch (errno) {
2359       case ENOENT:
2360          retval = bxattr_exit_ok;
2361          goto bail_out;
2362       default:
2363          Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2364                target_attrname, jcr->last_fname, be.bstrerror());
2365          Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2366                target_attrname, jcr->last_fname, be.bstrerror());
2367          goto bail_out;
2368       }
2369    }
2370
2371    /*
2372     * Based on the filetype perform the correct action. We support most filetypes here, more
2373     * then the actual implementation on Solaris supports so some code may never get executed
2374     * due to limitations in the implementation.
2375     */
2376    switch (st.st_mode & S_IFMT) {
2377    case S_IFIFO:
2378    case S_IFCHR:
2379    case S_IFBLK:
2380       /*
2381        * Get any acl on the xattr.
2382        */
2383       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2384          goto bail_out;
2385
2386       /*
2387        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2388        * Encode the stat struct into an ASCII representation.
2389        */
2390       encode_stat(attribs, &st, 0, stream);
2391       cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2392                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2393       break;
2394    case S_IFDIR:
2395       /*
2396        * Get any acl on the xattr.
2397        */
2398       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2399          goto bail_out;
2400
2401       /*
2402        * See if this is the toplevel_hidden_dir being saved.
2403        */
2404       if (toplevel_hidden_dir) {
2405          /*
2406           * Save the data for later storage when we encounter a real xattr. We store the data
2407           * in the jcr->xattr_data->content buffer and flush that just before sending out the
2408           * first real xattr. Encode the stat struct into an ASCII representation and jump
2409           * out of the function.
2410           */
2411          encode_stat(attribs, &st, 0, stream);
2412          cnt = bsnprintf(buffer, sizeof(buffer),
2413                          "%s%c%s%c%s%c",
2414                          target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2415          pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2416          jcr->xattr_data->content_length = cnt;
2417          goto bail_out;
2418       } else {
2419          /*
2420           * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2421           * Encode the stat struct into an ASCII representation.
2422           */
2423          encode_stat(attribs, &st, 0, stream);
2424          cnt = bsnprintf(buffer, sizeof(buffer),
2425                          "%s%c%s%c%s%c",
2426                          target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2427       }
2428       break;
2429    case S_IFREG:
2430       /*
2431        * If this is a hardlinked file check the inode cache for a hit.
2432        */
2433       if (st.st_nlink > 1) {
2434          /*
2435           * See if the cache already knows this inode number.
2436           */
2437          if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2438             /*
2439              * Generate a xattr encoding with the reference to the target in there.
2440              */
2441             encode_stat(attribs, &st, st.st_ino, stream);
2442             cnt = bsnprintf(buffer, sizeof(buffer),
2443                             "%s%c%s%c%s%c",
2444                             target_attrname, 0, attribs, 0, xlce->target, 0);
2445             pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2446             jcr->xattr_data->content_length = cnt;
2447             retval = send_xattr_stream(jcr, stream);
2448
2449             /*
2450              * For a hard linked file we are ready now, no need to recursively save the attributes.
2451              */
2452             goto bail_out;
2453          }
2454
2455          /*
2456           * Store this hard linked file in the cache.
2457           * Store the name relative to the top level xattr space.
2458           */
2459          add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2460       }
2461
2462       /*
2463        * Get any acl on the xattr.
2464        */
2465       if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2466          goto bail_out;
2467       }
2468
2469       /*
2470        * Encode the stat struct into an ASCII representation.
2471        */
2472       encode_stat(attribs, &st, 0, stream);
2473       cnt = bsnprintf(buffer, sizeof(buffer),
2474                      "%s%c%s%c%s%c",
2475                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2476
2477       /*
2478        * Open the extended or extensible attribute file.
2479        */
2480       if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2481          switch (errno) {
2482          case ENOENT:
2483             retval = bxattr_exit_ok;
2484             goto bail_out;
2485          default:
2486             Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2487                   target_attrname, jcr->last_fname, be.bstrerror());
2488             Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2489                   target_attrname, jcr->last_fname, be.bstrerror());
2490             goto bail_out;
2491          }
2492       }
2493       break;
2494    case S_IFLNK:
2495       /*
2496        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2497        * Encode the stat struct into an ASCII representation.
2498        */
2499       if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2500          switch (errno) {
2501          case ENOENT:
2502             retval = bxattr_exit_ok;
2503             goto bail_out;
2504          default:
2505             Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2506                   target_attrname, jcr->last_fname, be.bstrerror());
2507             Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2508                   target_attrname, jcr->last_fname, be.bstrerror());
2509             goto bail_out;
2510          }
2511       }
2512
2513       /*
2514        * Generate a xattr encoding with the reference to the target in there.
2515        */
2516       encode_stat(attribs, &st, st.st_ino, stream);
2517       cnt = bsnprintf(buffer, sizeof(buffer),
2518                       "%s%c%s%c%s%c",
2519                       target_attrname, 0, attribs, 0, link_source, 0);
2520       pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2521       jcr->xattr_data->content_length = cnt;
2522       retval = send_xattr_stream(jcr, stream);
2523
2524       if (retval == bxattr_exit_ok) {
2525          jcr->xattr_data->nr_saved++;
2526       }
2527
2528       /*
2529        * For a soft linked file we are ready now, no need to recursively save the attributes.
2530        */
2531       goto bail_out;
2532    default:
2533       goto bail_out;
2534    }
2535
2536    /*
2537     * See if this is the first real xattr being saved.
2538     * If it is save the toplevel_hidden_dir attributes first.
2539     * This is easy as its stored already in the jcr->xattr_data->content buffer.
2540     */
2541    if (jcr->xattr_data->nr_saved == 0) {
2542       retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2543       if (retval != bxattr_exit_ok) {
2544          goto bail_out;
2545       }
2546       jcr->xattr_data->nr_saved++;
2547    }
2548
2549    pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2550    jcr->xattr_data->content_length = cnt;
2551
2552    /*
2553     * Only dump the content of regular files.
2554     */
2555    switch (st.st_mode & S_IFMT) {
2556    case S_IFREG:
2557       if (st.st_size > 0) {
2558          /*
2559           * Protect ourself against things getting out of hand.
2560           */
2561          if (st.st_size >= MAX_XATTR_STREAM) {
2562             Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2563                   jcr->last_fname, MAX_XATTR_STREAM);
2564             goto bail_out;
2565          }
2566
2567          while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2568             jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
2569             memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
2570             jcr->xattr_data->content_length += cnt;
2571          }
2572
2573          if (cnt < 0) {
2574             Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
2575                   target_attrname, jcr->last_fname);
2576             Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2577                   target_attrname, jcr->last_fname);
2578             goto bail_out;
2579          }
2580       }
2581       break;
2582
2583    default:
2584       break;
2585    }
2586
2587    if (retval) {
2588       retval = send_xattr_stream(jcr, stream);
2589       if (retval == bxattr_exit_ok) {
2590          jcr->xattr_data->nr_saved++;
2591       }
2592    }
2593
2594    /*
2595     * Recursivly call solaris_save_extended_attributes for archiving the attributes
2596     * available on this extended attribute.
2597     */
2598    if (retval) {
2599       retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2600       
2601       /*
2602        * The recursive call could change our working dir so change back to the wanted workdir.
2603        */
2604       if (fchdir(fd) < 0) {
2605          switch (errno) {
2606          case ENOENT:
2607             retval = bxattr_exit_ok;
2608             goto bail_out;
2609          default:
2610             Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2611                   jcr->last_fname, be.bstrerror());
2612             Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2613                   jcr->last_fname, fd, be.bstrerror());
2614             goto bail_out;
2615          }
2616       }
2617    }
2618
2619 bail_out:
2620    if (acl_text != NULL) {
2621       free(acl_text);
2622    }
2623    if (attrfd != -1) {
2624       close(attrfd);
2625    }
2626    return retval;
2627 }
2628
2629 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2630 {
2631    const char *name;
2632    int fd, filefd = -1, attrdirfd = -1;
2633    DIR *dirp;
2634    struct dirent *dp;
2635    char current_xattr_namespace[PATH_MAX];
2636    bxattr_exit_code retval = bxattr_exit_error;
2637    berrno be;
2638  
2639    /*
2640     * Determine what argument to use. Use attr_parent when set
2641     * (recursive call) or jcr->last_fname for first call. Also save
2642     * the current depth of the xattr_space we are in.
2643     */
2644    if (attr_parent) {
2645       name = attr_parent;
2646       if (xattr_namespace) {
2647          bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2648                    xattr_namespace, attr_parent);
2649       } else {
2650          bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2651       }
2652    } else {
2653       name = jcr->last_fname;
2654       bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2655    }
2656
2657    /*
2658     * Open the file on which to save the xattrs read-only.
2659     */
2660    if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2661       switch (errno) {
2662       case ENOENT:
2663          retval = bxattr_exit_ok;
2664          goto bail_out;
2665       default:
2666          Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2667                jcr->last_fname, be.bstrerror());
2668          Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2669                jcr->last_fname, be.bstrerror());
2670          goto bail_out;
2671       }
2672    }
2673
2674    /*
2675     * Open the xattr naming space.
2676     */
2677    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2678       switch (errno) {
2679       case EINVAL:
2680          /*
2681           * Gentile way of the system saying this type of xattr layering is not supported.
2682           * Which is not problem we just forget about this this xattr.
2683           * But as this is not an error we return a positive return value.
2684           */
2685          retval = bxattr_exit_ok;
2686          goto bail_out;
2687       case ENOENT:
2688          retval = bxattr_exit_ok;
2689          goto bail_out;
2690       default:
2691          Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2692                name, jcr->last_fname, be.bstrerror());
2693          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2694                name, jcr->last_fname, be.bstrerror());
2695          goto bail_out;
2696       }
2697    }
2698
2699   /*
2700    * We need to change into the attribute directory to determine if each of the
2701    * attributes should be saved.
2702    */
2703    if (fchdir(attrdirfd) < 0) {
2704       Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2705             jcr->last_fname, be.bstrerror());
2706       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2707             jcr->last_fname, attrdirfd, be.bstrerror());
2708       goto bail_out;
2709    }
2710
2711    /*
2712     * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2713     * else because the readdir returns "." entry after the extensible attr entry.
2714     * And as we want this entry before anything else we better just save its data.
2715     */
2716    if (!attr_parent)
2717       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2718                          true, STREAM_XATTR_SOLARIS);
2719
2720    if ((fd = dup(attrdirfd)) == -1 ||
2721        (dirp = fdopendir(fd)) == (DIR *)NULL) {
2722       Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2723             jcr->last_fname, be.bstrerror());
2724       Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
2725             jcr->last_fname, fd, be.bstrerror());
2726
2727       goto bail_out;
2728    }
2729
2730    /*
2731     * Walk the namespace.
2732     */
2733    while ((dp = readdir(dirp)) != NULL) {
2734       /*
2735        * Skip only the toplevel . dir.
2736        */
2737       if (!attr_parent && bstrcmp(dp->d_name, "."))
2738          continue;
2739
2740       /*
2741        * Skip all .. directories
2742        */
2743       if (bstrcmp(dp->d_name, ".."))
2744          continue;
2745
2746       Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2747          current_xattr_namespace, dp->d_name, jcr->last_fname);
2748
2749 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2750       /*
2751        * We are not interested in read-only extensible attributes.
2752        */
2753       if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2754          Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2755             current_xattr_namespace, dp->d_name, jcr->last_fname);
2756
2757          continue;
2758       }
2759
2760       /*
2761        * We are only interested in read-write extensible attributes
2762        * when they contain non-transient values.
2763        */
2764       if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2765          /*
2766           * Determine if there are non-transient system attributes at the toplevel.
2767           * We need to provide a fd to the open file.
2768           */
2769          if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2770             Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2771                current_xattr_namespace, dp->d_name, jcr->last_fname);
2772             continue;
2773          }
2774
2775          /*
2776           * Save the xattr.
2777           */
2778          solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2779                             false, STREAM_XATTR_SOLARIS_SYS);
2780          continue;
2781       }
2782 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2783
2784       /*
2785        * Save the xattr.
2786        */
2787       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2788                          false, STREAM_XATTR_SOLARIS);
2789    }
2790
2791    closedir(dirp);
2792    retval = bxattr_exit_ok;
2793
2794 bail_out:
2795    if (attrdirfd != -1)
2796       close(attrdirfd);
2797    if (filefd != -1)
2798       close(filefd);
2799    return retval;
2800 }
2801
2802 #ifdef HAVE_ACL
2803 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
2804 {
2805 #ifdef HAVE_EXTENDED_ACL
2806    int error;
2807    acl_t *aclp = NULL;
2808    berrno be;
2809
2810    if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
2811       Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
2812             jcr->last_fname);
2813       return bxattr_exit_error;
2814    }
2815
2816    if ((fd != -1 && facl_set(fd, aclp) != 0) ||
2817         acl_set(attrname, aclp) != 0) {
2818       Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2819             attrname, jcr->last_fname, be.bstrerror());
2820       Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2821             attrname, jcr->last_fname, be.bstrerror());
2822       return bxattr_exit_error;
2823    }
2824
2825    if (aclp) {
2826       acl_free(aclp);
2827    }
2828    return bxattr_exit_ok;
2829
2830 #else /* HAVE_EXTENDED_ACL */
2831    int n;
2832    aclent_t *acls = NULL;
2833    berrno be;
2834
2835    acls = aclfromtext(acl_text, &n);
2836    if (!acls) {
2837       if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
2838            acl(attrname, SETACL, n, acls) != 0) {
2839          Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2840                attrname, jcr->last_fname, be.bstrerror());
2841          Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2842                attrname, jcr->last_fname, be.bstrerror());
2843          return bxattr_exit_error;
2844       }
2845    }
2846
2847    if (acls) {
2848       free(acls);
2849    }
2850    return bxattr_exit_ok;
2851
2852 #endif /* HAVE_EXTENDED_ACL */
2853
2854 }
2855 #endif /* HAVE_ACL */
2856
2857 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
2858 {
2859    int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
2860    int used_bytes, total_bytes, cnt;
2861    char *bp, *target_attrname, *attribs;
2862    char *linked_target = NULL;
2863    char *acl_text = NULL;
2864    char *data = NULL;
2865    int32_t inum;
2866    struct stat st;
2867    struct timeval times[2];
2868    bxattr_exit_code retval = bxattr_exit_error;
2869    berrno be;
2870
2871    /*
2872     * Parse the xattr stream. First the part that is the same for all xattrs.
2873     */
2874    used_bytes = 0;
2875    total_bytes = jcr->xattr_data->content_length;
2876
2877    /*
2878     * The name of the target xattr has a leading / we are not interested
2879     * in that so skip it when decoding the string. We always start a the /
2880     * of the xattr space anyway.
2881     */
2882    target_attrname = jcr->xattr_data->content + 1;
2883    if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
2884        (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2885       goto parse_error;
2886    }
2887    attribs = ++bp;
2888
2889    /*
2890     * Open the file on which to restore the xattrs read-only.
2891     */
2892    if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
2893       Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2894             jcr->last_fname, be.bstrerror());
2895       Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2896             jcr->last_fname, be.bstrerror());
2897       goto bail_out;
2898    }
2899
2900    /*
2901     * Open the xattr naming space and make it the current working dir.
2902     */
2903    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2904       Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
2905             jcr->last_fname, be.bstrerror());
2906       Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
2907             jcr->last_fname, be.bstrerror());
2908       goto bail_out;
2909    }
2910
2911    if (fchdir(attrdirfd) < 0) {
2912       Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2913             jcr->last_fname, be.bstrerror());
2914       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2915             jcr->last_fname, attrdirfd, be.bstrerror());
2916       goto bail_out;
2917    }
2918
2919    /*
2920     * Try to open the correct xattr subdir based on the target_attrname given.
2921     * e.g. check if its a subdir attrname. Each / in the string makes us go
2922     * one level deeper.
2923     */
2924    while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2925       *bp = '\0';
2926
2927       if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2928          Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2929                target_attrname, jcr->last_fname, be.bstrerror());
2930          Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2931                target_attrname, jcr->last_fname, be.bstrerror());
2932          goto bail_out;
2933       }
2934
2935       close(filefd);
2936       filefd = fd;
2937
2938       /*
2939        * Open the xattr naming space.
2940        */
2941       if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2942          Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2943                target_attrname, jcr->last_fname, be.bstrerror());
2944          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2945                target_attrname, jcr->last_fname, be.bstrerror());
2946          goto bail_out;
2947       }
2948
2949       close(attrdirfd);
2950       attrdirfd = fd;
2951
2952       /*
2953        * Make the xattr space our current workingdir.
2954        */
2955       if (fchdir(attrdirfd) < 0) {
2956          Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2957                target_attrname, jcr->last_fname, be.bstrerror());
2958          Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2959                target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2960          goto bail_out;
2961       }
2962
2963       target_attrname = ++bp;
2964    }
2965
2966    /*
2967     * Decode the attributes from the stream.
2968     */
2969    decode_stat(attribs, &st, &inum);
2970
2971    /*
2972     * Decode the next field (acl_text).
2973     */
2974    if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2975        (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2976       goto parse_error;
2977    }
2978    acl_text = ++bp;
2979
2980    /*
2981     * Based on the filetype perform the correct action. We support most filetypes here, more
2982     * then the actual implementation on Solaris supports so some code may never get executed
2983     * due to limitations in the implementation.
2984     */
2985    switch (st.st_mode & S_IFMT) {
2986    case S_IFIFO:
2987       /*
2988        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2989        */
2990       unlinkat(attrdirfd, target_attrname, 0);
2991       if (mkfifo(target_attrname, st.st_mode) < 0) {
2992          Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
2993                target_attrname, jcr->last_fname, be.bstrerror());
2994          Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
2995                target_attrname,  jcr->last_fname, be.bstrerror());
2996          goto bail_out;
2997       }
2998       break;
2999    case S_IFCHR:
3000    case S_IFBLK:
3001       /*
3002        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3003        */
3004       unlinkat(attrdirfd, target_attrname, 0);
3005       if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3006          Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3007                target_attrname, jcr->last_fname, be.bstrerror());
3008          Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3009                target_attrname,  jcr->last_fname, be.bstrerror());
3010          goto bail_out;
3011       }
3012       break;
3013    case S_IFDIR:
3014       /*
3015        * If its not the hidden_dir create the entry.
3016        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3017        */
3018       if (!bstrcmp(target_attrname, ".")) {
3019          unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3020          if (mkdir(target_attrname, st.st_mode) < 0) {
3021             Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3022                target_attrname, jcr->last_fname, be.bstrerror());
3023             Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3024                target_attrname,  jcr->last_fname, be.bstrerror());
3025             goto bail_out;
3026          }
3027       }
3028       break;
3029    case S_IFREG:
3030       /*
3031        * See if this is a hard linked file. e.g. inum != 0
3032        */
3033       if (inum != 0) {
3034          linked_target = bp;
3035
3036          unlinkat(attrdirfd, target_attrname, 0);
3037          if (link(linked_target, target_attrname) < 0) {
3038             Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3039                   target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3040             Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3041                   target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3042             goto bail_out;
3043          }
3044
3045          /*
3046           * Successfully restored xattr.
3047           */
3048          retval = bxattr_exit_ok;
3049          goto bail_out;
3050       } else {
3051          if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3052              (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
3053             goto parse_error;
3054          }
3055
3056          if (used_bytes < (total_bytes - 1))
3057             data = ++bp;
3058
3059          /*
3060           * Restore the actual xattr.
3061           */
3062          if (!is_extensible) {
3063             unlinkat(attrdirfd, target_attrname, 0);
3064          }
3065
3066          if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3067             Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3068                   target_attrname, jcr->last_fname, be.bstrerror());
3069             Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3070                   target_attrname, jcr->last_fname, be.bstrerror());
3071             goto bail_out;
3072          }
3073       }
3074
3075       /*
3076        * Restore the actual data.
3077        */
3078       if (st.st_size > 0) {
3079          used_bytes = (data - jcr->xattr_data->content);
3080          cnt = total_bytes - used_bytes;
3081
3082          /*
3083           * Do a sanity check, the st.st_size should be the same as the number of bytes
3084           * we have available as data of the stream.
3085           */
3086          if (cnt != st.st_size) {
3087             Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3088                   target_attrname, jcr->last_fname);
3089             Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3090                   target_attrname, jcr->last_fname);
3091             goto bail_out;
3092          }
3093
3094          while (cnt > 0) {
3095             cnt = write(attrfd, data, cnt);
3096             if (cnt < 0) {
3097                Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3098                      target_attrname, jcr->last_fname, be.bstrerror());
3099                Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3100                      target_attrname, jcr->last_fname, be.bstrerror());
3101                goto bail_out;
3102             }
3103
3104             used_bytes += cnt;
3105             data += cnt;
3106             cnt = total_bytes - used_bytes;
3107          }
3108       }
3109       break;
3110    case S_IFLNK:
3111       /*
3112        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3113        */
3114       linked_target = bp;
3115
3116       if (symlink(linked_target, target_attrname) < 0) {
3117          Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3118                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3119          Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3120                target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3121          goto bail_out;
3122       }
3123
3124       /*
3125        * Successfully restored xattr.
3126        */
3127       retval = bxattr_exit_ok;
3128       goto bail_out;
3129    default:
3130       goto bail_out;
3131    }
3132
3133    /*
3134     * Restore owner and acl for non extensible attributes.
3135     */
3136    if (!is_extensible) {
3137       if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3138          switch (errno) {
3139          case EINVAL:
3140             /*
3141              * Gentile way of the system saying this type of xattr layering is not supported.
3142              * But as this is not an error we return a positive return value.
3143              */
3144             retval = bxattr_exit_ok;
3145             break;
3146          case ENOENT:
3147             retval = bxattr_exit_ok;
3148             break;
3149          default:
3150             Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3151                   target_attrname, jcr->last_fname, be.bstrerror());
3152             Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3153                   target_attrname, jcr->last_fname, be.bstrerror());
3154          }
3155          goto bail_out;
3156       }
3157    }
3158
3159 #ifdef HAVE_ACL
3160    if (acl_text && *acl_text)
3161       if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3162          goto bail_out;
3163 #endif /* HAVE_ACL */
3164
3165    /*
3166     * For a non extensible attribute restore access and modification time on the xattr.
3167     */
3168    if (!is_extensible) {
3169       times[0].tv_sec = st.st_atime;
3170       times[0].tv_usec = 0;
3171       times[1].tv_sec = st.st_mtime;
3172       times[1].tv_usec = 0;
3173
3174       if (futimesat(attrdirfd, target_attrname, times) < 0) {
3175          Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3176                target_attrname, jcr->last_fname, be.bstrerror());
3177          Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3178                target_attrname, jcr->last_fname, be.bstrerror());
3179          goto bail_out;
3180       }
3181    }
3182
3183    /*
3184     * Successfully restored xattr.
3185     */
3186    retval = bxattr_exit_ok;
3187    goto bail_out;
3188
3189 parse_error:
3190    Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3191          jcr->last_fname);
3192    Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3193          jcr->last_fname);
3194
3195 bail_out:
3196    if (attrfd != -1) {
3197       close(attrfd);
3198    }
3199    if (attrdirfd != -1) {
3200       close(attrdirfd);
3201    }
3202    if (filefd != -1) {
3203       close(filefd);
3204    }
3205    return retval;
3206 }
3207
3208 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3209 {
3210    char cwd[PATH_MAX];
3211    bxattr_exit_code retval = bxattr_exit_ok;
3212
3213    /*
3214     * First see if extended attributes or extensible attributes are present.
3215     * If not just pretend things went ok.
3216     */
3217    if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3218       jcr->xattr_data->nr_saved = 0;
3219       jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
3220
3221       /*
3222        * As we change the cwd in the save function save the current cwd
3223        * for restore after return from the solaris_save_xattrs function.
3224        */
3225       getcwd(cwd, sizeof(cwd));
3226       retval = solaris_save_xattrs(jcr, NULL, NULL);
3227       chdir(cwd);
3228       delete jcr->xattr_data->link_cache;
3229       jcr->xattr_data->link_cache = NULL;
3230    }
3231    return retval;
3232 }
3233
3234 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
3235 {
3236    char cwd[PATH_MAX];
3237    bool is_extensible = false;
3238    bxattr_exit_code retval;
3239
3240    /*
3241     * First make sure we can restore xattr on the filesystem.
3242     */
3243    switch (stream) {
3244 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3245    case STREAM_XATTR_SOLARIS_SYS:
3246       if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3247          Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
3248          Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3249             jcr->last_fname);
3250          return bxattr_exit_error;
3251       }
3252
3253       is_extensible = true;
3254       break;
3255 #endif
3256    case STREAM_XATTR_SOLARIS:
3257       if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3258          Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
3259          Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3260             jcr->last_fname);
3261          return bxattr_exit_error;
3262       }
3263       break;
3264    default:
3265       return bxattr_exit_error;
3266    }
3267
3268    /*
3269     * As we change the cwd in the restore function save the current cwd
3270     * for restore after return from the solaris_restore_xattrs function.
3271     */
3272    getcwd(cwd, sizeof(cwd));
3273    retval = solaris_restore_xattrs(jcr, is_extensible);
3274    chdir(cwd);
3275    return retval;
3276 }
3277
3278
3279 /*
3280  * Function pointers to the build and parse function to use for these xattrs.
3281  */
3282 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
3283 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
3284
3285 #endif /* defined(HAVE_SUN_OS) */
3286
3287 /*
3288  * Entry points when compiled with support for XATTRs on a supported platform.
3289  */
3290 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3291 {
3292    if (os_build_xattr_streams) {
3293       return (*os_build_xattr_streams)(jcr, ff_pkt);
3294    }
3295    return bxattr_exit_error;
3296 }
3297
3298 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
3299 {
3300    unsigned int cnt;
3301
3302    if (os_parse_xattr_streams) {
3303       /*
3304        * See if we can parse this stream, and ifso give it a try.
3305        */
3306       for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3307          if (os_default_xattr_streams[cnt] == stream) {
3308             return (*os_parse_xattr_streams)(jcr, stream);
3309          }
3310       }
3311    }
3312    /*
3313     * Issue a warning and discard the message. But pretend the restore was ok.
3314     */
3315    Jmsg2(jcr, M_WARNING, 0,
3316       _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3317       jcr->last_fname, stream);
3318    return bxattr_exit_error;
3319 }
3320 #endif