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