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