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