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