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