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