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