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