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