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