2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2010 Free Software Foundation Europe e.V.
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
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.
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
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.
29 * Functions to handle Extended Attributes for bacula.
31 * Extended Attributes are so OS specific we only restore Extended Attributes if
32 * they were saved using a filed on the same platform.
34 * Currently we support the following OSes:
35 * - AIX (Extended Attributes)
36 * - Darwin (Extended Attributes)
37 * - Linux (Extended Attributes)
38 * - NetBSD (Extended Attributes)
39 * - FreeBSD (Extended Attributes)
40 * - OpenBSD (Extended Attributes)
41 * (As it seems either they never implemented xattr or they are removed
42 * the support as it stated it was in version 3.1 but the current syscall
43 * tabled shows the extattr_ functions are not implemented. So as such we
44 * might eventually support xattr on OpenBSD when they implemented them using
45 * the same interface as FreeBSD and NetBSD.
46 * - Solaris (Extended Attributes and Extensible Attributes)
48 * Written by Marco van Wieringen, November MMVIII
55 #if !defined(HAVE_XATTR)
57 * Entry points when compiled without support for XATTRs or on an unsupported platform.
59 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
61 return bxattr_exit_fatal;
64 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
66 return bxattr_exit_fatal;
70 * Send a XATTR stream to the SD.
72 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
74 BSOCK *sd = jcr->store_bsock;
76 #ifdef FD_NO_SEND_TEST
77 return bxattr_exit_ok;
83 if (jcr->xattr_data->content_length <= 0) {
84 return bxattr_exit_ok;
90 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
91 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
93 return bxattr_exit_fatal;
97 * Send the buffer to the storage deamon
99 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
101 sd->msg = jcr->xattr_data->content;
102 sd->msglen = jcr->xattr_data->content_length;
106 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
108 return bxattr_exit_fatal;
111 jcr->JobBytes += sd->msglen;
113 if (!sd->signal(BNET_EOD)) {
114 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
116 return bxattr_exit_fatal;
118 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
119 return bxattr_exit_ok;
123 * First some generic functions for OSes that use the same xattr encoding scheme.
125 #if defined(HAVE_AIX_OS) || \
126 defined(HAVE_DARWIN_OS) || \
127 defined(HAVE_LINUX_OS) || \
128 defined(HAVE_NETBSD_OS) || \
129 defined(HAVE_FREEBSD_OS) || \
130 defined(HAVE_OPENBSD_OS)
132 static void xattr_drop_internal_table(alist *xattr_value_list)
134 xattr_t *current_xattr;
137 * Walk the list of xattrs and free allocated memory on traversing.
139 foreach_alist(current_xattr, xattr_value_list) {
141 * See if we can shortcut.
143 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
146 free(current_xattr->name);
148 if (current_xattr->value_length > 0)
149 free(current_xattr->value);
154 delete xattr_value_list;
158 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
159 * which encodes one or more xattr_t structures.
161 * The Serialized stream consists of the following elements:
162 * magic - A magic string which makes it easy to detect any binary incompatabilites
163 * name_length - The length of the following xattr name
164 * name - The name of the extended attribute
165 * value_length - The length of the following xattr data
166 * value - The actual content of the extended attribute
168 * This is repeated 1 or more times.
171 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, alist *xattr_value_list)
173 xattr_t *current_xattr;
177 * Make sure the serialized stream fits in the poolmem buffer.
178 * We allocate some more to be sure the stream is gonna fit.
180 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
181 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
184 * Walk the list of xattrs and serialize the data.
186 foreach_alist(current_xattr, xattr_value_list) {
188 * See if we can shortcut.
190 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
193 ser_uint32(current_xattr->magic);
194 ser_uint32(current_xattr->name_length);
195 ser_bytes(current_xattr->name, current_xattr->name_length);
197 ser_uint32(current_xattr->value_length);
198 if (current_xattr->value_length > 0 && current_xattr->value) {
199 ser_bytes(current_xattr->value, current_xattr->value_length);
203 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
204 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
206 return jcr->xattr_data->content_length;
209 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
212 xattr_t *current_xattr;
213 bxattr_exit_code retval = bxattr_exit_ok;
216 * Parse the stream and call restore_xattr_on_file for each extended attribute.
218 * Start unserializing the data. We keep on looping while we have not
219 * unserialized all bytes in the stream.
221 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
222 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
224 * First make sure the magic is present. This way we can easily catch corruption.
225 * Any missing MAGIC is fatal we do NOT try to continue.
228 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
229 unser_uint32(current_xattr->magic);
230 if (current_xattr->magic != XATTR_MAGIC) {
231 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
233 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
236 return bxattr_exit_error;
240 * Decode the valuepair. First decode the length of the name.
242 unser_uint32(current_xattr->name_length);
243 if (current_xattr->name_length == 0) {
244 Mmsg1(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
246 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
249 return bxattr_exit_error;
253 * Allocate room for the name and decode its content.
255 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
256 unser_bytes(current_xattr->name, current_xattr->name_length);
259 * The xattr_name needs to be null terminated.
261 current_xattr->name[current_xattr->name_length] = '\0';
264 * Decode the value length.
266 unser_uint32(current_xattr->value_length);
268 if (current_xattr->value_length > 0) {
270 * Allocate room for the value and decode its content.
272 current_xattr->value = (char *)malloc(current_xattr->value_length);
273 unser_bytes(current_xattr->value, current_xattr->value_length);
275 current_xattr->value = NULL;
278 xattr_value_list->append(current_xattr);
281 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
287 * This is a supported OS, See what kind of interface we should use.
289 #if defined(HAVE_AIX_OS)
291 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
292 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
293 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
294 #error "Missing full support for the Extended Attributes (EA) functions."
300 #error "Missing sys/ea.h header file"
304 * Define the supported XATTR streams for this OS
306 static int os_default_xattr_streams[1] = { STREAM_XATTR_AIX };
309 * Fallback to the non l-functions when those are not available.
311 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
314 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
317 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
318 #define llistea listea
321 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
324 char *xattr_list, *bp;
325 int cnt, xattr_count = 0;
326 uint32_t name_length;
327 int32_t xattr_list_len,
329 uint32_t expected_serialize_len = 0;
330 xattr_t *current_xattr;
331 alist *xattr_value_list = NULL;
332 bxattr_exit_code retval = bxattr_exit_error;
336 * First get the length of the available list with extended attributes.
338 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
339 switch (xattr_list_len) {
345 return bxattr_exit_ok;
347 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
348 jcr->last_fname, be.bstrerror());
349 Dmsg2(100, "llistea error file=%s ERR=%s\n",
350 jcr->last_fname, be.bstrerror());
351 return bxattr_exit_error;
355 return bxattr_exit_ok;
361 * Allocate room for the extented attribute list.
363 xattr_list = (char *)malloc(xattr_list_len + 1);
364 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
367 * Get the actual list of extended attributes names for a file.
369 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
370 switch (xattr_list_len) {
376 retval = bxattr_exit_ok;
379 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
380 jcr->last_fname, be.bstrerror());
381 Dmsg2(100, "llistea error file=%s ERR=%s\n",
382 jcr->last_fname, be.bstrerror());
389 xattr_list[xattr_list_len] = '\0';
391 xattr_value_list = New(alist(10, not_owned_by_alist));
394 * Walk the list of extended attributes names and retrieve the data.
395 * We already count the bytes needed for serializing the stream later on.
398 while ((bp - xattr_list) + 1 < xattr_list_len) {
402 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
408 name_length = strlen(bp);
409 if (skip_xattr || name_length == 0) {
410 bp = strchr(bp, '\0') + 1;
415 * Each xattr valuepair starts with a magic so we can parse it easier.
417 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
418 current_xattr->magic = XATTR_MAGIC;
419 expected_serialize_len += sizeof(current_xattr->magic);
422 * Allocate space for storing the name.
424 current_xattr->name_length = name_length;
425 current_xattr->name = (char *)malloc(current_xattr->name_length);
426 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
428 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
431 * First see how long the value is for the extended attribute.
433 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
434 switch (xattr_value_len) {
440 retval = bxattr_exit_ok;
441 free(current_xattr->name);
445 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
446 jcr->last_fname, be.bstrerror());
447 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
448 jcr->last_fname, be.bstrerror());
449 free(current_xattr->name);
455 current_xattr->value = NULL;
456 current_xattr->value_length = 0;
457 expected_serialize_len += sizeof(current_xattr->value_length);
461 * Allocate space for storing the value.
463 current_xattr->value = (char *)malloc(xattr_value_len);
464 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
466 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
467 if (xattr_value_len < 0) {
472 retval = bxattr_exit_ok;
473 free(current_xattr->value);
474 free(current_xattr->name);
478 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
479 jcr->last_fname, be.bstrerror());
480 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
481 jcr->last_fname, be.bstrerror());
482 free(current_xattr->value);
483 free(current_xattr->name);
489 * Store the actual length of the value.
491 current_xattr->value_length = xattr_value_len;
492 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
495 * Protect ourself against things getting out of hand.
497 if (expected_serialize_len >= MAX_XATTR_STREAM) {
498 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
499 jcr->last_fname, MAX_XATTR_STREAM);
500 free(current_xattr->value);
501 free(current_xattr->name);
507 xattr_value_list->append(current_xattr);
509 bp = strchr(bp, '\0') + 1;
514 xattr_list = (char *)NULL;
517 * If we found any xattr send them to the SD.
519 if (xattr_count > 0) {
521 * Serialize the datastream.
523 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
524 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
526 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
531 xattr_drop_internal_table(xattr_value_list);
534 * Send the datastream to the SD.
536 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
538 xattr_drop_internal_table(xattr_value_list);
540 return bxattr_exit_ok;
544 if (xattr_list != NULL) {
547 if (xattr_value_list != NULL) {
548 xattr_drop_internal_table(xattr_value_list);
553 static bxattr_exit_code aix_xattr_parse_streams(JCR *jcr, int stream)
555 xattr_t *current_xattr;
556 alist *xattr_value_list;
559 xattr_value_list = New(alist(10, not_owned_by_alist));
561 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
562 xattr_drop_internal_table(xattr_value_list);
563 return bxattr_exit_error;
566 foreach_alist(current_xattr, xattr_value_list) {
567 if (lsetea(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
574 Mmsg2(jcr->errmsg, _("lsetea error on file \"%s\": ERR=%s\n"),
575 jcr->last_fname, be.bstrerror());
576 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
577 jcr->last_fname, be.bstrerror());
583 xattr_drop_internal_table(xattr_value_list);
584 return bxattr_exit_ok;
587 xattr_drop_internal_table(xattr_value_list);
588 return bxattr_exit_error;
592 * Function pointers to the build and parse function to use for these xattrs.
594 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_xattr_build_streams;
595 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = aix_xattr_parse_streams;
597 #elif defined(HAVE_DARWIN_OS) || \
598 defined(HAVE_LINUX_OS)
600 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
601 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
602 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
603 #error "Missing full support for the XATTR functions."
606 #ifdef HAVE_SYS_XATTR_H
607 #include <sys/xattr.h>
609 #error "Missing sys/xattr.h header file"
613 * Define the supported XATTR streams for this OS
615 #if defined(HAVE_DARWIN_OS)
616 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
617 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
618 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
619 #elif defined(HAVE_LINUX_OS)
620 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
621 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
622 static const char *xattr_skiplist[1] = { NULL };
626 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
627 * listxattr, getxattr and setxattr with an extra options argument
628 * which mimics the l variants of the functions when we specify
629 * XATTR_NOFOLLOW as the options value.
631 #if defined(HAVE_DARWIN_OS)
632 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
633 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
634 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
637 * Fallback to the non l-functions when those are not available.
639 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
640 #define lgetxattr getxattr
642 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
643 #define lsetxattr setxattr
645 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
646 #define llistxattr listxattr
650 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
653 char *xattr_list, *bp;
654 int cnt, xattr_count = 0;
655 int32_t xattr_list_len,
657 uint32_t expected_serialize_len = 0;
658 xattr_t *current_xattr;
659 alist *xattr_value_list = NULL;
660 bxattr_exit_code retval = bxattr_exit_error;
664 * First get the length of the available list with extended attributes.
666 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
667 switch (xattr_list_len) {
672 return bxattr_exit_ok;
674 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
675 jcr->last_fname, be.bstrerror());
676 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
677 jcr->last_fname, be.bstrerror());
678 return bxattr_exit_error;
682 return bxattr_exit_ok;
688 * Allocate room for the extented attribute list.
690 xattr_list = (char *)malloc(xattr_list_len + 1);
691 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
694 * Get the actual list of extended attributes names for a file.
696 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
697 switch (xattr_list_len) {
702 retval = bxattr_exit_ok;
705 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
706 jcr->last_fname, be.bstrerror());
707 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
708 jcr->last_fname, be.bstrerror());
715 xattr_list[xattr_list_len] = '\0';
717 xattr_value_list = New(alist(10, not_owned_by_alist));
720 * Walk the list of extended attributes names and retrieve the data.
721 * We already count the bytes needed for serializing the stream later on.
724 while ((bp - xattr_list) + 1 < xattr_list_len) {
729 * On some OSes you also get the acls in the extented attribute list.
730 * So we check if we are already backing up acls and if we do we
731 * don't store the extended attribute with the same info.
733 if (ff_pkt->flags & FO_ACL) {
734 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
735 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
743 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
746 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
747 if (bstrcmp(bp, xattr_skiplist[cnt])) {
754 name_len = strlen(bp);
755 if (skip_xattr || name_len == 0) {
756 bp = strchr(bp, '\0') + 1;
761 * Each xattr valuepair starts with a magic so we can parse it easier.
763 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
764 current_xattr->magic = XATTR_MAGIC;
765 expected_serialize_len += sizeof(current_xattr->magic);
768 * Allocate space for storing the name.
770 current_xattr->name_length = name_len;
771 current_xattr->name = (char *)malloc(current_xattr->name_length);
772 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
774 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
777 * First see how long the value is for the extended attribute.
779 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
780 switch (xattr_value_len) {
785 retval = bxattr_exit_ok;
786 free(current_xattr->name);
790 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
791 jcr->last_fname, be.bstrerror());
792 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
793 jcr->last_fname, be.bstrerror());
794 free(current_xattr->name);
800 current_xattr->value = NULL;
801 current_xattr->value_length = 0;
802 expected_serialize_len += sizeof(current_xattr->value_length);
806 * Allocate space for storing the value.
808 current_xattr->value = (char *)malloc(xattr_value_len);
809 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
811 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
812 if (xattr_value_len < 0) {
816 retval = bxattr_exit_ok;
817 free(current_xattr->value);
818 free(current_xattr->name);
822 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
823 jcr->last_fname, be.bstrerror());
824 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
825 jcr->last_fname, be.bstrerror());
826 free(current_xattr->value);
827 free(current_xattr->name);
833 * Store the actual length of the value.
835 current_xattr->value_length = xattr_value_len;
836 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
839 * Protect ourself against things getting out of hand.
841 if (expected_serialize_len >= MAX_XATTR_STREAM) {
842 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
843 jcr->last_fname, MAX_XATTR_STREAM);
844 free(current_xattr->value);
845 free(current_xattr->name);
851 xattr_value_list->append(current_xattr);
853 bp = strchr(bp, '\0') + 1;
858 xattr_list = (char *)NULL;
861 * If we found any xattr send them to the SD.
863 if (xattr_count > 0) {
865 * Serialize the datastream.
867 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
868 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
870 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
875 xattr_drop_internal_table(xattr_value_list);
878 * Send the datastream to the SD.
880 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
882 xattr_drop_internal_table(xattr_value_list);
884 return bxattr_exit_ok;
888 if (xattr_list != NULL) {
891 if (xattr_value_list != NULL) {
892 xattr_drop_internal_table(xattr_value_list);
897 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
899 xattr_t *current_xattr;
900 alist *xattr_value_list;
903 xattr_value_list = New(alist(10, not_owned_by_alist));
905 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
906 xattr_drop_internal_table(xattr_value_list);
907 return bxattr_exit_error;
910 foreach_alist(current_xattr, xattr_value_list) {
911 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
917 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
918 jcr->last_fname, be.bstrerror());
919 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
920 jcr->last_fname, be.bstrerror());
926 xattr_drop_internal_table(xattr_value_list);
927 return bxattr_exit_ok;
930 xattr_drop_internal_table(xattr_value_list);
931 return bxattr_exit_error;
935 * Function pointers to the build and parse function to use for these xattrs.
937 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
938 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
940 #elif defined(HAVE_FREEBSD_OS) || \
941 defined(HAVE_NETBSD_OS) || \
942 defined(HAVE_OPENBSD_OS)
944 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
945 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
946 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
947 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
948 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
949 #error "Missing full support for the extattr functions."
952 #ifdef HAVE_SYS_EXTATTR_H
953 #include <sys/extattr.h>
955 #error "Missing sys/extattr.h header file"
958 #ifdef HAVE_LIBUTIL_H
962 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
963 #define extattr_get_link extattr_get_file
965 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
966 #define extattr_set_link extattr_set_file
968 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
969 #define extattr_list_link extattr_list_file
972 #if defined(HAVE_FREEBSD_OS)
973 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
974 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
975 static const char *xattr_acl_skiplist[2] = { "system.posix1e.acl_access", NULL };
976 static const char *xattr_skiplist[1] = { NULL };
977 #elif defined(HAVE_NETBSD_OS)
978 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
979 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
980 static const char *xattr_acl_skiplist[1] = { NULL };
981 static const char *xattr_skiplist[1] = { NULL };
982 #elif defined(HAVE_OPENBSD_OS)
983 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
984 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
985 static const char *xattr_acl_skiplist[1] = { NULL };
986 static const char *xattr_skiplist[1] = { NULL };
989 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
993 int cnt, index, xattr_count = 0;
994 int32_t xattr_list_len,
996 uint32_t expected_serialize_len = 0;
997 unsigned int namespace_index;
999 char *current_attrnamespace = NULL;
1000 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1001 xattr_t *current_xattr;
1002 alist *xattr_value_list = NULL;
1003 bxattr_exit_code retval = bxattr_exit_error;
1006 xattr_value_list = New(alist(10, not_owned_by_alist));
1009 * Loop over all available xattr namespaces.
1011 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
1012 attrnamespace = os_default_xattr_namespaces[namespace_index];
1015 * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
1016 * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
1018 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1019 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
1020 attrnamespace, jcr->last_fname);
1021 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1022 attrnamespace, jcr->last_fname);
1027 * First get the length of the available list with extended attributes.
1028 * If we get EPERM on system namespace, don't return error.
1029 * This is expected for normal users trying to archive the system
1030 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1031 * they've decided to return EOPNOTSUPP instead.
1033 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1034 switch (xattr_list_len) {
1038 retval = bxattr_exit_ok;
1040 #if defined(EOPNOTSUPP)
1044 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1045 actuallyfree(current_attrnamespace);
1046 current_attrnamespace = NULL;
1053 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1054 jcr->last_fname, be.bstrerror());
1055 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1056 jcr->last_fname, be.bstrerror());
1067 * Allocate room for the extented attribute list.
1069 xattr_list = (char *)malloc(xattr_list_len + 1);
1070 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
1073 * Get the actual list of extended attributes names for a file.
1075 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
1076 switch (xattr_list_len) {
1080 retval = bxattr_exit_ok;
1083 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1084 jcr->last_fname, be.bstrerror());
1085 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1086 jcr->last_fname, be.bstrerror());
1093 xattr_list[xattr_list_len] = '\0';
1096 * Walk the list of extended attributes names and retrieve the data.
1097 * We already count the bytes needed for serializing the stream later on.
1099 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1103 * Print the current name into the buffer as its not null terminated we need to
1104 * use the length encoded in the string for copying only the needed bytes.
1106 cnt = xattr_list[index];
1107 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1108 cnt = ((int)sizeof(current_attrname) - 1);
1110 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1111 current_attrname[cnt] = '\0';
1114 * First make a xattr tuple of the current namespace and the name of the xattr.
1115 * e.g. something like user.<attrname> or system.<attrname>
1117 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
1120 * On some OSes you also get the acls in the extented attribute list.
1121 * So we check if we are already backing up acls and if we do we
1122 * don't store the extended attribute with the same info.
1124 if (ff_pkt->flags & FO_ACL) {
1125 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1126 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1134 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1137 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1138 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1150 * Each xattr valuepair starts with a magic so we can parse it easier.
1152 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1153 current_xattr->magic = XATTR_MAGIC;
1154 expected_serialize_len += sizeof(current_xattr->magic);
1157 * Allocate space for storing the name.
1159 current_xattr->name_length = strlen(current_attrtuple);
1160 current_xattr->name = (char *)malloc(current_xattr->name_length);
1161 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
1163 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1166 * First see how long the value is for the extended attribute.
1168 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
1169 switch (xattr_value_len) {
1173 retval = bxattr_exit_ok;
1174 free(current_xattr->name);
1175 free(current_xattr);
1178 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1179 jcr->last_fname, be.bstrerror());
1180 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1181 jcr->last_fname, be.bstrerror());
1182 free(current_xattr->name);
1183 free(current_xattr);
1188 current_xattr->value = NULL;
1189 current_xattr->value_length = 0;
1190 expected_serialize_len += sizeof(current_xattr->value_length);
1194 * Allocate space for storing the value.
1196 current_xattr->value = (char *)malloc(xattr_value_len);
1197 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1199 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
1200 if (xattr_value_len < 0) {
1203 retval = bxattr_exit_ok;
1204 free(current_xattr->value);
1205 free(current_xattr->name);
1206 free(current_xattr);
1209 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1210 jcr->last_fname, be.bstrerror());
1211 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1212 jcr->last_fname, be.bstrerror());
1213 free(current_xattr->value);
1214 free(current_xattr->name);
1215 free(current_xattr);
1221 * Store the actual length of the value.
1223 current_xattr->value_length = xattr_value_len;
1224 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1227 * Protect ourself against things getting out of hand.
1229 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1230 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1231 jcr->last_fname, MAX_XATTR_STREAM);
1232 free(current_xattr->value);
1233 free(current_xattr->name);
1234 free(current_xattr);
1240 xattr_value_list->append(current_xattr);
1246 * Drop the local copy of the current_attrnamespace.
1248 actuallyfree(current_attrnamespace);
1249 current_attrnamespace = NULL;
1252 * We are done with this xattr list.
1255 xattr_list = (char *)NULL;
1259 * If we found any xattr send them to the SD.
1261 if (xattr_count > 0) {
1263 * Serialize the datastream.
1265 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1266 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1268 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1273 xattr_drop_internal_table(xattr_value_list);
1276 * Send the datastream to the SD.
1278 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
1280 xattr_drop_internal_table(xattr_value_list);
1282 return bxattr_exit_ok;
1286 if (current_attrnamespace != NULL) {
1287 actuallyfree(current_attrnamespace);
1289 if (xattr_list != NULL) {
1292 if (xattr_value_list != NULL) {
1293 xattr_drop_internal_table(xattr_value_list);
1298 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
1300 xattr_t *current_xattr;
1301 alist *xattr_value_list;
1302 int current_attrnamespace, cnt;
1303 char *attrnamespace, *attrname;
1306 xattr_value_list = New(alist(10, not_owned_by_alist));
1308 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1309 xattr_drop_internal_table(xattr_value_list);
1310 return bxattr_exit_error;
1313 foreach_alist(current_xattr, xattr_value_list) {
1315 * Try splitting the xattr_name into a namespace and name part.
1316 * The splitting character is a .
1318 attrnamespace = current_xattr->name;
1319 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1320 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1321 current_xattr->name, jcr->last_fname);
1322 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1323 current_xattr->name, jcr->last_fname);
1329 * Make sure the attrnamespace makes sense.
1331 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1332 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1333 attrnamespace, jcr->last_fname);
1334 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1335 attrnamespace, jcr->last_fname);
1340 * Try restoring the extended attribute.
1342 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1343 attrname, current_xattr->value, current_xattr->value_length);
1344 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1350 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1351 jcr->last_fname, be.bstrerror());
1352 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1353 jcr->last_fname, be.bstrerror());
1360 xattr_drop_internal_table(xattr_value_list);
1361 return bxattr_exit_ok;
1364 xattr_drop_internal_table(xattr_value_list);
1365 return bxattr_exit_error;
1369 * Function pointers to the build and parse function to use for these xattrs.
1371 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1372 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1374 #elif defined(HAVE_SUN_OS)
1376 * Solaris extended attributes were introduced in Solaris 9
1379 * Solaris extensible attributes were introduced in OpenSolaris
1380 * by PSARC 2007/315 Solaris extensible attributes are also
1381 * sometimes called extended system attributes.
1383 * man fsattr(5) on Solaris gives a wealth of info. The most
1384 * important bits are:
1386 * Attributes are logically supported as files within the file
1387 * system. The file system is therefore augmented with an
1388 * orthogonal name space of file attributes. Any file (includ-
1389 * ing attribute files) can have an arbitrarily deep attribute
1390 * tree associated with it. Attribute values are accessed by
1391 * file descriptors obtained through a special attribute inter-
1392 * face. This logical view of "attributes as files" allows the
1393 * leveraging of existing file system interface functionality
1394 * to support the construction, deletion, and manipulation of
1397 * The special files "." and ".." retain their accustomed
1398 * semantics within the attribute hierarchy. The "." attribute
1399 * file refers to the current directory and the ".." attribute
1400 * file refers to the parent directory. The unnamed directory
1401 * at the head of each attribute tree is considered the "child"
1402 * of the file it is associated with and the ".." file refers
1403 * to the associated file. For any non-directory file with
1404 * attributes, the ".." entry in the unnamed directory refers
1405 * to a file that is not a directory.
1407 * Conceptually, the attribute model is fully general. Extended
1408 * attributes can be any type of file (doors, links, direc-
1409 * tories, and so forth) and can even have their own attributes
1410 * (fully recursive). As a result, the attributes associated
1411 * with a file could be an arbitrarily deep directory hierarchy
1412 * where each attribute could have an equally complex attribute
1413 * tree associated with it. Not all implementations are able
1414 * to, or want to, support the full model. Implementation are
1415 * therefore permitted to reject operations that are not sup-
1416 * ported. For example, the implementation for the UFS file
1417 * system allows only regular files as attributes (for example,
1418 * no sub-directories) and rejects attempts to place attributes
1421 * The following list details the operations that are rejected
1422 * in the current implementation:
1424 * link Any attempt to create links between
1425 * attribute and non-attribute space
1426 * is rejected to prevent security-
1427 * related or otherwise sensitive
1428 * attributes from being exposed, and
1429 * therefore manipulable, as regular
1432 * rename Any attempt to rename between
1433 * attribute and non-attribute space
1434 * is rejected to prevent an already
1435 * linked file from being renamed and
1436 * thereby circumventing the link res-
1439 * mkdir, symlink, mknod Any attempt to create a "non-
1440 * regular" file in attribute space is
1441 * rejected to reduce the functional-
1442 * ity, and therefore exposure and
1443 * risk, of the initial implementa-
1446 * The entire available name space has been allocated to "gen-
1447 * eral use" to bring the implementation in line with the NFSv4
1448 * draft standard [NFSv4]. That standard defines "named attri-
1449 * butes" (equivalent to Solaris Extended Attributes) with no
1450 * naming restrictions. All Sun applications making use of
1451 * opaque extended attributes will use the prefix "SUNW".
1454 #ifdef HAVE_SYS_ATTR_H
1455 #include <sys/attr.h>
1462 #ifdef HAVE_SYS_NVPAIR_H
1463 #include <sys/nvpair.h>
1466 #ifdef HAVE_SYS_ACL_H
1467 #include <sys/acl.h>
1470 #if !defined(HAVE_OPENAT) || \
1471 !defined(HAVE_UNLINKAT) || \
1472 !defined(HAVE_FCHOWNAT) || \
1473 !defined(HAVE_FUTIMESAT)
1474 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
1478 * Define the supported XATTR streams for this OS
1480 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1481 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
1483 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
1484 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
1487 * This code creates a temporary cache with entries for each xattr which has
1488 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
1490 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
1492 xattr_link_cache_entry_t *ptr;
1494 foreach_alist(ptr, jcr->xattr_data->link_cache) {
1495 if (ptr && ptr->inum == inum) {
1502 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
1504 xattr_link_cache_entry_t *ptr;
1506 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
1507 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
1509 bstrncpy(ptr->target, target, sizeof(ptr->target));
1510 jcr->xattr_data->link_cache->append(ptr);
1513 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1515 * This function returns true if a non default extended system attribute
1516 * list is associated with fd and returns false when an error has occured
1517 * or when only extended system attributes other than archive,
1518 * av_modified or crtime are set.
1520 * The function returns true for the following cases:
1522 * - any extended system attribute other than the default attributes
1523 * ('archive', 'av_modified' and 'crtime') is set
1524 * - nvlist has NULL name string
1525 * - nvpair has data type of 'nvlist'
1526 * - default data type.
1528 static bool solaris_has_non_transient_extensible_attributes(int fd)
1536 bool retval = false;
1538 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
1543 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
1544 name = nvpair_name(pair);
1547 fattr = name_to_attr(name);
1553 type = nvpair_type(pair);
1555 case DATA_TYPE_BOOLEAN_VALUE:
1556 if (nvpair_value_boolean_value(pair, &value) != 0) {
1559 if (value && fattr != F_ARCHIVE &&
1560 fattr != F_AV_MODIFIED) {
1565 case DATA_TYPE_UINT64_ARRAY:
1566 if (fattr != F_CRTIME) {
1571 case DATA_TYPE_NVLIST:
1579 if (response != NULL) {
1580 nvlist_free(response);
1584 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1586 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
1588 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1589 * There is no need to store those acls as we already store the stat bits too.
1591 static bool acl_is_trivial(int count, aclent_t *entries)
1596 for (n = 0; n < count; n++) {
1598 if (!(ace->a_type == USER_OBJ ||
1599 ace->a_type == GROUP_OBJ ||
1600 ace->a_type == OTHER_OBJ ||
1601 ace->a_type == CLASS_OBJ))
1606 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
1608 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
1611 #ifdef HAVE_EXTENDED_ACL
1617 * See if this attribute has an ACL
1619 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
1620 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
1622 * See if there is a non trivial acl on the file.
1624 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
1625 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
1628 return bxattr_exit_ok;
1630 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1631 attrname, jcr->last_fname, be.bstrerror());
1632 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
1633 attrname, jcr->last_fname, be.bstrerror());
1634 return bxattr_exit_error;
1639 #if defined(ACL_SID_FMT)
1641 * New format flag added in newer Solaris versions.
1643 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1645 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1646 #endif /* ACL_SID_FMT */
1648 *acl_text = acl_totext(aclp, flags);
1656 return bxattr_exit_ok;
1657 #else /* HAVE_EXTENDED_ACL */
1659 aclent_t *acls = NULL;
1663 * See if this attribute has an ACL
1666 n = facl(fd, GETACLCNT, 0, NULL);
1668 n = acl(attrname, GETACLCNT, 0, NULL);
1671 if (n >= MIN_ACL_ENTRIES) {
1672 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1673 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
1674 acl(attrname, GETACL, n, acls) != n) {
1678 return bxattr_exit_ok;
1680 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1681 attrname, jcr->last_fname, be.bstrerror());
1682 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
1683 attrname, jcr->last_fname, be.bstrerror());
1685 return bxattr_exit_error;
1690 * See if there is a non trivial acl on the file.
1692 if (!acl_is_trivial(n, acls)) {
1693 if ((*acl_text = acltotext(acls, n)) == NULL) {
1694 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
1695 attrname, jcr->last_fname, be.bstrerror());
1696 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
1697 attrname, jcr->last_fname, be.bstrerror());
1699 return bxattr_exit_error;
1709 return bxattr_exit_ok;
1710 #endif /* HAVE_EXTENDED_ACL */
1712 #else /* HAVE_ACL */
1713 return bxattr_exit_ok;
1714 #endif /* HAVE_ACL */
1718 * Forward declaration for recursive function call.
1720 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
1723 * Save an extended or extensible attribute.
1724 * This is stored as an opaque stream of bytes with the following encoding:
1726 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
1728 * or for a hardlinked or symlinked attribute
1730 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
1732 * xattr_name can be a subpath relative to the file the xattr is on.
1733 * stat_buffer is the string representation of the stat struct.
1734 * acl_string is an acl text when a non trivial acl is set on the xattr.
1735 * actual_xattr_data is the content of the xattr file.
1737 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
1738 const char *attrname, bool toplevel_hidden_dir, int stream)
1743 xattr_link_cache_entry_t *xlce;
1744 char target_attrname[PATH_MAX];
1745 char link_source[PATH_MAX];
1746 char *acl_text = NULL;
1747 char attribs[MAXSTRING];
1748 char buffer[XATTR_BUFSIZ];
1749 bxattr_exit_code retval = bxattr_exit_error;
1752 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
1755 * Get the stats of the extended or extensible attribute.
1757 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
1760 retval = bxattr_exit_ok;
1763 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
1764 target_attrname, jcr->last_fname, be.bstrerror());
1765 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
1766 target_attrname, jcr->last_fname, be.bstrerror());
1772 * Based on the filetype perform the correct action. We support most filetypes here, more
1773 * then the actual implementation on Solaris supports so some code may never get executed
1774 * due to limitations in the implementation.
1776 switch (st.st_mode & S_IFMT) {
1781 * Get any acl on the xattr.
1783 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1787 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1788 * Encode the stat struct into an ASCII representation.
1790 encode_stat(attribs, &st, 0, stream);
1791 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
1792 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1796 * Get any acl on the xattr.
1798 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1802 * See if this is the toplevel_hidden_dir being saved.
1804 if (toplevel_hidden_dir) {
1806 * Save the data for later storage when we encounter a real xattr. We store the data
1807 * in the jcr->xattr_data->content buffer and flush that just before sending out the
1808 * first real xattr. Encode the stat struct into an ASCII representation and jump
1809 * out of the function.
1811 encode_stat(attribs, &st, 0, stream);
1812 cnt = bsnprintf(buffer, sizeof(buffer),
1814 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1815 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1816 jcr->xattr_data->content_length = cnt;
1820 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1821 * Encode the stat struct into an ASCII representation.
1823 encode_stat(attribs, &st, 0, stream);
1824 cnt = bsnprintf(buffer, sizeof(buffer),
1826 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1831 * If this is a hardlinked file check the inode cache for a hit.
1833 if (st.st_nlink > 1) {
1835 * See if the cache already knows this inode number.
1837 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
1839 * Generate a xattr encoding with the reference to the target in there.
1841 encode_stat(attribs, &st, st.st_ino, stream);
1842 cnt = bsnprintf(buffer, sizeof(buffer),
1844 target_attrname, 0, attribs, 0, xlce->target, 0);
1845 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1846 jcr->xattr_data->content_length = cnt;
1847 retval = send_xattr_stream(jcr, stream);
1850 * For a hard linked file we are ready now, no need to recursively save the attributes.
1856 * Store this hard linked file in the cache.
1857 * Store the name relative to the top level xattr space.
1859 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
1863 * Get any acl on the xattr.
1865 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
1870 * Encode the stat struct into an ASCII representation.
1872 encode_stat(attribs, &st, 0, stream);
1873 cnt = bsnprintf(buffer, sizeof(buffer),
1875 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1878 * Open the extended or extensible attribute file.
1880 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1883 retval = bxattr_exit_ok;
1886 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1887 target_attrname, jcr->last_fname, be.bstrerror());
1888 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1889 target_attrname, jcr->last_fname, be.bstrerror());
1896 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1897 * Encode the stat struct into an ASCII representation.
1899 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1902 retval = bxattr_exit_ok;
1905 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1906 target_attrname, jcr->last_fname, be.bstrerror());
1907 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1908 target_attrname, jcr->last_fname, be.bstrerror());
1914 * Generate a xattr encoding with the reference to the target in there.
1916 encode_stat(attribs, &st, st.st_ino, stream);
1917 cnt = bsnprintf(buffer, sizeof(buffer),
1919 target_attrname, 0, attribs, 0, link_source, 0);
1920 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1921 jcr->xattr_data->content_length = cnt;
1922 retval = send_xattr_stream(jcr, stream);
1924 if (retval == bxattr_exit_ok) {
1925 jcr->xattr_data->nr_saved++;
1929 * For a soft linked file we are ready now, no need to recursively save the attributes.
1937 * See if this is the first real xattr being saved.
1938 * If it is save the toplevel_hidden_dir attributes first.
1939 * This is easy as its stored already in the jcr->xattr_data->content buffer.
1941 if (jcr->xattr_data->nr_saved == 0) {
1942 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1943 if (retval != bxattr_exit_ok) {
1946 jcr->xattr_data->nr_saved++;
1949 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1950 jcr->xattr_data->content_length = cnt;
1953 * Only dump the content of regular files.
1955 switch (st.st_mode & S_IFMT) {
1957 if (st.st_size > 0) {
1959 * Protect ourself against things getting out of hand.
1961 if (st.st_size >= MAX_XATTR_STREAM) {
1962 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1963 jcr->last_fname, MAX_XATTR_STREAM);
1967 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1968 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
1969 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
1970 jcr->xattr_data->content_length += cnt;
1974 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
1975 target_attrname, jcr->last_fname);
1976 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1977 target_attrname, jcr->last_fname);
1988 retval = send_xattr_stream(jcr, stream);
1989 if (retval == bxattr_exit_ok) {
1990 jcr->xattr_data->nr_saved++;
1995 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1996 * available on this extended attribute.
1999 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2002 * The recursive call could change our working dir so change back to the wanted workdir.
2004 if (fchdir(fd) < 0) {
2007 retval = bxattr_exit_ok;
2010 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2011 jcr->last_fname, be.bstrerror());
2012 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2013 jcr->last_fname, fd, be.bstrerror());
2020 if (acl_text != NULL) {
2029 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2032 int fd, filefd = -1, attrdirfd = -1;
2035 char current_xattr_namespace[PATH_MAX];
2036 bxattr_exit_code retval = bxattr_exit_error;
2040 * Determine what argument to use. Use attr_parent when set
2041 * (recursive call) or jcr->last_fname for first call. Also save
2042 * the current depth of the xattr_space we are in.
2046 if (xattr_namespace) {
2047 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2048 xattr_namespace, attr_parent);
2050 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2053 name = jcr->last_fname;
2054 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2058 * Open the file on which to save the xattrs read-only.
2060 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2063 retval = bxattr_exit_ok;
2066 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2067 jcr->last_fname, be.bstrerror());
2068 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2069 jcr->last_fname, be.bstrerror());
2075 * Open the xattr naming space.
2077 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2081 * Gentile way of the system saying this type of xattr layering is not supported.
2082 * Which is not problem we just forget about this this xattr.
2083 * But as this is not an error we return a positive return value.
2085 retval = bxattr_exit_ok;
2088 retval = bxattr_exit_ok;
2091 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2092 name, jcr->last_fname, be.bstrerror());
2093 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2094 name, jcr->last_fname, be.bstrerror());
2100 * We need to change into the attribute directory to determine if each of the
2101 * attributes should be saved.
2103 if (fchdir(attrdirfd) < 0) {
2104 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2105 jcr->last_fname, be.bstrerror());
2106 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2107 jcr->last_fname, attrdirfd, be.bstrerror());
2112 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2113 * else because the readdir returns "." entry after the extensible attr entry.
2114 * And as we want this entry before anything else we better just save its data.
2117 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2118 true, STREAM_XATTR_SOLARIS);
2120 if ((fd = dup(attrdirfd)) == -1 ||
2121 (dirp = fdopendir(fd)) == (DIR *)NULL) {
2122 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2123 jcr->last_fname, be.bstrerror());
2124 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
2125 jcr->last_fname, fd, be.bstrerror());
2131 * Walk the namespace.
2133 while ((dp = readdir(dirp)) != NULL) {
2135 * Skip only the toplevel . dir.
2137 if (!attr_parent && bstrcmp(dp->d_name, "."))
2141 * Skip all .. directories
2143 if (bstrcmp(dp->d_name, ".."))
2146 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2147 current_xattr_namespace, dp->d_name, jcr->last_fname);
2149 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2151 * We are not interested in read-only extensible attributes.
2153 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2154 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2155 current_xattr_namespace, dp->d_name, jcr->last_fname);
2161 * We are only interested in read-write extensible attributes
2162 * when they contain non-transient values.
2164 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2166 * Determine if there are non-transient system attributes at the toplevel.
2167 * We need to provide a fd to the open file.
2169 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2170 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2171 current_xattr_namespace, dp->d_name, jcr->last_fname);
2178 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2179 false, STREAM_XATTR_SOLARIS_SYS);
2182 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2187 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2188 false, STREAM_XATTR_SOLARIS);
2192 retval = bxattr_exit_ok;
2195 if (attrdirfd != -1)
2203 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
2205 #ifdef HAVE_EXTENDED_ACL
2210 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
2211 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
2213 return bxattr_exit_error;
2216 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
2217 acl_set(attrname, aclp) != 0) {
2218 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2219 attrname, jcr->last_fname, be.bstrerror());
2220 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2221 attrname, jcr->last_fname, be.bstrerror());
2222 return bxattr_exit_error;
2228 return bxattr_exit_ok;
2230 #else /* HAVE_EXTENDED_ACL */
2232 aclent_t *acls = NULL;
2235 acls = aclfromtext(acl_text, &n);
2237 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
2238 acl(attrname, SETACL, n, acls) != 0) {
2239 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2240 attrname, jcr->last_fname, be.bstrerror());
2241 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2242 attrname, jcr->last_fname, be.bstrerror());
2243 return bxattr_exit_error;
2250 return bxattr_exit_ok;
2252 #endif /* HAVE_EXTENDED_ACL */
2255 #endif /* HAVE_ACL */
2257 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
2259 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
2260 int used_bytes, total_bytes, cnt;
2261 char *bp, *target_attrname, *attribs;
2262 char *linked_target = NULL;
2263 char *acl_text = NULL;
2267 struct timeval times[2];
2268 bxattr_exit_code retval = bxattr_exit_error;
2272 * Parse the xattr stream. First the part that is the same for all xattrs.
2275 total_bytes = jcr->xattr_data->content_length;
2278 * The name of the target xattr has a leading / we are not interested
2279 * in that so skip it when decoding the string. We always start a the /
2280 * of the xattr space anyway.
2282 target_attrname = jcr->xattr_data->content + 1;
2283 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
2284 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2290 * Open the file on which to restore the xattrs read-only.
2292 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
2293 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2294 jcr->last_fname, be.bstrerror());
2295 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2296 jcr->last_fname, be.bstrerror());
2301 * Open the xattr naming space and make it the current working dir.
2303 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2304 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
2305 jcr->last_fname, be.bstrerror());
2306 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
2307 jcr->last_fname, be.bstrerror());
2311 if (fchdir(attrdirfd) < 0) {
2312 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2313 jcr->last_fname, be.bstrerror());
2314 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2315 jcr->last_fname, attrdirfd, be.bstrerror());
2320 * Try to open the correct xattr subdir based on the target_attrname given.
2321 * e.g. check if its a subdir attrname. Each / in the string makes us go
2324 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2327 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2328 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2329 target_attrname, jcr->last_fname, be.bstrerror());
2330 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2331 target_attrname, jcr->last_fname, be.bstrerror());
2339 * Open the xattr naming space.
2341 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2342 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2343 target_attrname, jcr->last_fname, be.bstrerror());
2344 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2345 target_attrname, jcr->last_fname, be.bstrerror());
2353 * Make the xattr space our current workingdir.
2355 if (fchdir(attrdirfd) < 0) {
2356 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2357 target_attrname, jcr->last_fname, be.bstrerror());
2358 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2359 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2363 target_attrname = ++bp;
2367 * Decode the attributes from the stream.
2369 decode_stat(attribs, &st, &inum);
2372 * Decode the next field (acl_text).
2374 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2375 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2381 * Based on the filetype perform the correct action. We support most filetypes here, more
2382 * then the actual implementation on Solaris supports so some code may never get executed
2383 * due to limitations in the implementation.
2385 switch (st.st_mode & S_IFMT) {
2388 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2390 unlinkat(attrdirfd, target_attrname, 0);
2391 if (mkfifo(target_attrname, st.st_mode) < 0) {
2392 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
2393 target_attrname, jcr->last_fname, be.bstrerror());
2394 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
2395 target_attrname, jcr->last_fname, be.bstrerror());
2402 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2404 unlinkat(attrdirfd, target_attrname, 0);
2405 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
2406 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
2407 target_attrname, jcr->last_fname, be.bstrerror());
2408 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
2409 target_attrname, jcr->last_fname, be.bstrerror());
2415 * If its not the hidden_dir create the entry.
2416 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2418 if (!bstrcmp(target_attrname, ".")) {
2419 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
2420 if (mkdir(target_attrname, st.st_mode) < 0) {
2421 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
2422 target_attrname, jcr->last_fname, be.bstrerror());
2423 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
2424 target_attrname, jcr->last_fname, be.bstrerror());
2431 * See if this is a hard linked file. e.g. inum != 0
2436 unlinkat(attrdirfd, target_attrname, 0);
2437 if (link(linked_target, target_attrname) < 0) {
2438 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
2439 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2440 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
2441 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2446 * Successfully restored xattr.
2448 retval = bxattr_exit_ok;
2451 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
2452 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
2456 if (used_bytes < (total_bytes - 1))
2460 * Restore the actual xattr.
2462 if (!is_extensible) {
2463 unlinkat(attrdirfd, target_attrname, 0);
2466 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
2467 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2468 target_attrname, jcr->last_fname, be.bstrerror());
2469 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2470 target_attrname, jcr->last_fname, be.bstrerror());
2476 * Restore the actual data.
2478 if (st.st_size > 0) {
2479 used_bytes = (data - jcr->xattr_data->content);
2480 cnt = total_bytes - used_bytes;
2483 * Do a sanity check, the st.st_size should be the same as the number of bytes
2484 * we have available as data of the stream.
2486 if (cnt != st.st_size) {
2487 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
2488 target_attrname, jcr->last_fname);
2489 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
2490 target_attrname, jcr->last_fname);
2495 cnt = write(attrfd, data, cnt);
2497 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
2498 target_attrname, jcr->last_fname, be.bstrerror());
2499 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
2500 target_attrname, jcr->last_fname, be.bstrerror());
2506 cnt = total_bytes - used_bytes;
2512 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2516 if (symlink(linked_target, target_attrname) < 0) {
2517 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
2518 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2519 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
2520 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2525 * Successfully restored xattr.
2527 retval = bxattr_exit_ok;
2534 * Restore owner and acl for non extensible attributes.
2536 if (!is_extensible) {
2537 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
2541 * Gentile way of the system saying this type of xattr layering is not supported.
2542 * But as this is not an error we return a positive return value.
2544 retval = bxattr_exit_ok;
2547 retval = bxattr_exit_ok;
2550 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
2551 target_attrname, jcr->last_fname, be.bstrerror());
2552 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
2553 target_attrname, jcr->last_fname, be.bstrerror());
2560 if (acl_text && *acl_text)
2561 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
2563 #endif /* HAVE_ACL */
2566 * For a non extensible attribute restore access and modification time on the xattr.
2568 if (!is_extensible) {
2569 times[0].tv_sec = st.st_atime;
2570 times[0].tv_usec = 0;
2571 times[1].tv_sec = st.st_mtime;
2572 times[1].tv_usec = 0;
2574 if (futimesat(attrdirfd, target_attrname, times) < 0) {
2575 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
2576 target_attrname, jcr->last_fname, be.bstrerror());
2577 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
2578 target_attrname, jcr->last_fname, be.bstrerror());
2584 * Successfully restored xattr.
2586 retval = bxattr_exit_ok;
2590 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
2592 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
2599 if (attrdirfd != -1) {
2608 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2611 bxattr_exit_code retval = bxattr_exit_ok;
2614 * First see if extended attributes or extensible attributes are present.
2615 * If not just pretend things went ok.
2617 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
2618 jcr->xattr_data->nr_saved = 0;
2619 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
2622 * As we change the cwd in the save function save the current cwd
2623 * for restore after return from the solaris_save_xattrs function.
2625 getcwd(cwd, sizeof(cwd));
2626 retval = solaris_save_xattrs(jcr, NULL, NULL);
2628 delete jcr->xattr_data->link_cache;
2629 jcr->xattr_data->link_cache = NULL;
2634 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
2637 bool is_extensible = false;
2638 bxattr_exit_code retval;
2641 * First make sure we can restore xattr on the filesystem.
2644 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2645 case STREAM_XATTR_SOLARIS_SYS:
2646 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
2647 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
2648 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
2650 return bxattr_exit_error;
2653 is_extensible = true;
2656 case STREAM_XATTR_SOLARIS:
2657 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
2658 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
2659 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
2661 return bxattr_exit_error;
2665 return bxattr_exit_error;
2669 * As we change the cwd in the restore function save the current cwd
2670 * for restore after return from the solaris_restore_xattrs function.
2672 getcwd(cwd, sizeof(cwd));
2673 retval = solaris_restore_xattrs(jcr, is_extensible);
2680 * Function pointers to the build and parse function to use for these xattrs.
2682 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
2683 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
2685 #endif /* defined(HAVE_SUN_OS) */
2688 * Entry points when compiled with support for XATTRs on a supported platform.
2690 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2692 if (os_build_xattr_streams) {
2693 return (*os_build_xattr_streams)(jcr, ff_pkt);
2695 return bxattr_exit_error;
2698 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
2702 if (os_parse_xattr_streams) {
2704 * See if we can parse this stream, and ifso give it a try.
2706 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
2707 if (os_default_xattr_streams[cnt] == stream) {
2708 return (*os_parse_xattr_streams)(jcr, stream);
2713 * Issue a warning and discard the message. But pretend the restore was ok.
2715 Jmsg2(jcr, M_WARNING, 0,
2716 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
2717 jcr->last_fname, stream);
2718 return bxattr_exit_error;