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