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