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