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.
124 * Currently for all OSes except for Solaris.
126 #if !defined(HAVE_SUN_OS)
127 static void xattr_drop_internal_table(alist *xattr_value_list)
129 xattr_t *current_xattr;
132 * Walk the list of xattrs and free allocated memory on traversing.
134 foreach_alist(current_xattr, xattr_value_list) {
136 * See if we can shortcut.
138 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
141 free(current_xattr->name);
143 if (current_xattr->value_length > 0)
144 free(current_xattr->value);
149 delete xattr_value_list;
153 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
154 * which encodes one or more xattr_t structures.
156 * The Serialized stream consists of the following elements:
157 * magic - A magic string which makes it easy to detect any binary incompatabilites
158 * name_length - The length of the following xattr name
159 * name - The name of the extended attribute
160 * value_length - The length of the following xattr data
161 * value - The actual content of the extended attribute
163 * This is repeated 1 or more times.
166 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, alist *xattr_value_list)
168 xattr_t *current_xattr;
172 * Make sure the serialized stream fits in the poolmem buffer.
173 * We allocate some more to be sure the stream is gonna fit.
175 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
176 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
179 * Walk the list of xattrs and serialize the data.
181 foreach_alist(current_xattr, xattr_value_list) {
183 * See if we can shortcut.
185 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
188 ser_uint32(current_xattr->magic);
189 ser_uint32(current_xattr->name_length);
190 ser_bytes(current_xattr->name, current_xattr->name_length);
192 ser_uint32(current_xattr->value_length);
193 if (current_xattr->value_length > 0 && current_xattr->value) {
194 ser_bytes(current_xattr->value, current_xattr->value_length);
198 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
199 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
201 return jcr->xattr_data->content_length;
204 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
207 xattr_t *current_xattr;
208 bxattr_exit_code retval = bxattr_exit_ok;
211 * Parse the stream and call restore_xattr_on_file for each extended attribute.
213 * Start unserializing the data. We keep on looping while we have not
214 * unserialized all bytes in the stream.
216 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
217 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
219 * First make sure the magic is present. This way we can easily catch corruption.
220 * Any missing MAGIC is fatal we do NOT try to continue.
223 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
224 unser_uint32(current_xattr->magic);
225 if (current_xattr->magic != XATTR_MAGIC) {
226 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
228 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
231 return bxattr_exit_error;
235 * Decode the valuepair. First decode the length of the name.
237 unser_uint32(current_xattr->name_length);
238 if (current_xattr->name_length == 0) {
239 Mmsg1(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
241 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
244 return bxattr_exit_error;
248 * Allocate room for the name and decode its content.
250 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
251 unser_bytes(current_xattr->name, current_xattr->name_length);
254 * The xattr_name needs to be null terminated.
256 current_xattr->name[current_xattr->name_length] = '\0';
259 * Decode the value length.
261 unser_uint32(current_xattr->value_length);
263 if (current_xattr->value_length > 0) {
265 * Allocate room for the value and decode its content.
267 current_xattr->value = (char *)malloc(current_xattr->value_length);
268 unser_bytes(current_xattr->value, current_xattr->value_length);
270 current_xattr->value = NULL;
273 xattr_value_list->append(current_xattr);
276 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
282 * This is a supported OS, See what kind of interface we should use.
284 #if defined(HAVE_AIX_OS)
286 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
287 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
288 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
289 #error "Missing full support for the Extended Attributes (EA) functions."
295 #error "Missing sys/ea.h header file"
299 * Define the supported XATTR streams for this OS
301 static int os_default_xattr_streams[1] = { STREAM_XATTR_AIX };
304 * Fallback to the non l-functions when those are not available.
306 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
309 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
312 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
313 #define llistea listea
316 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
319 char *xattr_list, *bp;
320 int cnt, xattr_count = 0;
321 uint32_t name_length;
322 int32_t xattr_list_len,
324 uint32_t expected_serialize_len = 0;
325 xattr_t *current_xattr;
326 alist *xattr_value_list = NULL;
327 bxattr_exit_code retval = bxattr_exit_error;
331 * First get the length of the available list with extended attributes.
333 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
334 switch (xattr_list_len) {
340 return bxattr_exit_ok;
342 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
343 jcr->last_fname, be.bstrerror());
344 Dmsg2(100, "llistea error file=%s ERR=%s\n",
345 jcr->last_fname, be.bstrerror());
346 return bxattr_exit_error;
350 return bxattr_exit_ok;
356 * Allocate room for the extented attribute list.
358 xattr_list = (char *)malloc(xattr_list_len + 1);
359 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
362 * Get the actual list of extended attributes names for a file.
364 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
365 switch (xattr_list_len) {
371 retval = bxattr_exit_ok;
374 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
375 jcr->last_fname, be.bstrerror());
376 Dmsg2(100, "llistea error file=%s ERR=%s\n",
377 jcr->last_fname, be.bstrerror());
384 xattr_list[xattr_list_len] = '\0';
386 xattr_value_list = New(alist(10, not_owned_by_alist));
389 * Walk the list of extended attributes names and retrieve the data.
390 * We already count the bytes needed for serializing the stream later on.
393 while ((bp - xattr_list) + 1 < xattr_list_len) {
397 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
403 name_length = strlen(bp);
404 if (skip_xattr || name_length == 0) {
405 bp = strchr(bp, '\0') + 1;
410 * Each xattr valuepair starts with a magic so we can parse it easier.
412 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
413 current_xattr->magic = XATTR_MAGIC;
414 expected_serialize_len += sizeof(current_xattr->magic);
417 * Allocate space for storing the name.
419 current_xattr->name_length = name_length;
420 current_xattr->name = (char *)malloc(current_xattr->name_length);
421 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
423 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
426 * First see how long the value is for the extended attribute.
428 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
429 switch (xattr_value_len) {
435 retval = bxattr_exit_ok;
436 free(current_xattr->name);
440 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
441 jcr->last_fname, be.bstrerror());
442 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
443 jcr->last_fname, be.bstrerror());
444 free(current_xattr->name);
450 current_xattr->value = NULL;
451 current_xattr->value_length = 0;
452 expected_serialize_len += sizeof(current_xattr->value_length);
456 * Allocate space for storing the value.
458 current_xattr->value = (char *)malloc(xattr_value_len);
459 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
461 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
462 if (xattr_value_len < 0) {
467 retval = bxattr_exit_ok;
468 free(current_xattr->value);
469 free(current_xattr->name);
473 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
474 jcr->last_fname, be.bstrerror());
475 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
476 jcr->last_fname, be.bstrerror());
477 free(current_xattr->value);
478 free(current_xattr->name);
484 * Store the actual length of the value.
486 current_xattr->value_length = xattr_value_len;
487 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
490 * Protect ourself against things getting out of hand.
492 if (expected_serialize_len >= MAX_XATTR_STREAM) {
493 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
494 jcr->last_fname, MAX_XATTR_STREAM);
495 free(current_xattr->value);
496 free(current_xattr->name);
502 xattr_value_list->append(current_xattr);
504 bp = strchr(bp, '\0') + 1;
509 xattr_list = (char *)NULL;
512 * If we found any xattr send them to the SD.
514 if (xattr_count > 0) {
516 * Serialize the datastream.
518 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
519 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
521 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
526 xattr_drop_internal_table(xattr_value_list);
529 * Send the datastream to the SD.
531 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
533 xattr_drop_internal_table(xattr_value_list);
535 return bxattr_exit_ok;
539 if (xattr_list != NULL) {
542 if (xattr_value_list != NULL) {
543 xattr_drop_internal_table(xattr_value_list);
548 static bxattr_exit_code aix_xattr_parse_streams(JCR *jcr, int stream)
550 xattr_t *current_xattr;
551 alist *xattr_value_list;
554 xattr_value_list = New(alist(10, not_owned_by_alist));
556 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
557 xattr_drop_internal_table(xattr_value_list);
558 return bxattr_exit_error;
561 foreach_alist(current_xattr, xattr_value_list) {
562 if (lsetea(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
569 Mmsg2(jcr->errmsg, _("lsetea error on file \"%s\": ERR=%s\n"),
570 jcr->last_fname, be.bstrerror());
571 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
572 jcr->last_fname, be.bstrerror());
578 xattr_drop_internal_table(xattr_value_list);
579 return bxattr_exit_ok;
582 xattr_drop_internal_table(xattr_value_list);
583 return bxattr_exit_error;
587 * Function pointers to the build and parse function to use for these xattrs.
589 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_xattr_build_streams;
590 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = aix_xattr_parse_streams;
592 #elif defined(HAVE_DARWIN_OS) || \
593 defined(HAVE_LINUX_OS)
595 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
596 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
597 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
598 #error "Missing full support for the XATTR functions."
601 #ifdef HAVE_SYS_XATTR_H
602 #include <sys/xattr.h>
604 #error "Missing sys/xattr.h header file"
608 * Define the supported XATTR streams for this OS
610 #if defined(HAVE_DARWIN_OS)
611 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
612 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
613 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
614 #elif defined(HAVE_LINUX_OS)
615 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
616 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
617 static const char *xattr_skiplist[1] = { NULL };
621 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
622 * listxattr, getxattr and setxattr with an extra options argument
623 * which mimics the l variants of the functions when we specify
624 * XATTR_NOFOLLOW as the options value.
626 #if defined(HAVE_DARWIN_OS)
627 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
628 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
629 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
632 * Fallback to the non l-functions when those are not available.
634 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
635 #define lgetxattr getxattr
637 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
638 #define lsetxattr setxattr
640 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
641 #define llistxattr listxattr
645 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
648 char *xattr_list, *bp;
649 int cnt, xattr_count = 0;
650 int32_t xattr_list_len,
652 uint32_t expected_serialize_len = 0;
653 xattr_t *current_xattr;
654 alist *xattr_value_list = NULL;
655 bxattr_exit_code retval = bxattr_exit_error;
659 * First get the length of the available list with extended attributes.
661 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
662 switch (xattr_list_len) {
667 return bxattr_exit_ok;
669 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
670 jcr->last_fname, be.bstrerror());
671 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
672 jcr->last_fname, be.bstrerror());
673 return bxattr_exit_error;
677 return bxattr_exit_ok;
683 * Allocate room for the extented attribute list.
685 xattr_list = (char *)malloc(xattr_list_len + 1);
686 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
689 * Get the actual list of extended attributes names for a file.
691 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
692 switch (xattr_list_len) {
697 retval = bxattr_exit_ok;
700 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
701 jcr->last_fname, be.bstrerror());
702 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
703 jcr->last_fname, be.bstrerror());
710 xattr_list[xattr_list_len] = '\0';
712 xattr_value_list = New(alist(10, not_owned_by_alist));
715 * Walk the list of extended attributes names and retrieve the data.
716 * We already count the bytes needed for serializing the stream later on.
719 while ((bp - xattr_list) + 1 < xattr_list_len) {
724 * On some OSes you also get the acls in the extented attribute list.
725 * So we check if we are already backing up acls and if we do we
726 * don't store the extended attribute with the same info.
728 if (ff_pkt->flags & FO_ACL) {
729 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
730 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
738 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
741 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
742 if (bstrcmp(bp, xattr_skiplist[cnt])) {
749 name_len = strlen(bp);
750 if (skip_xattr || name_len == 0) {
751 bp = strchr(bp, '\0') + 1;
756 * Each xattr valuepair starts with a magic so we can parse it easier.
758 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
759 current_xattr->magic = XATTR_MAGIC;
760 expected_serialize_len += sizeof(current_xattr->magic);
763 * Allocate space for storing the name.
765 current_xattr->name_length = name_len;
766 current_xattr->name = (char *)malloc(current_xattr->name_length);
767 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
769 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
772 * First see how long the value is for the extended attribute.
774 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
775 switch (xattr_value_len) {
780 retval = bxattr_exit_ok;
781 free(current_xattr->name);
785 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
786 jcr->last_fname, be.bstrerror());
787 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
788 jcr->last_fname, be.bstrerror());
789 free(current_xattr->name);
795 current_xattr->value = NULL;
796 current_xattr->value_length = 0;
797 expected_serialize_len += sizeof(current_xattr->value_length);
801 * Allocate space for storing the value.
803 current_xattr->value = (char *)malloc(xattr_value_len);
804 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
806 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
807 if (xattr_value_len < 0) {
811 retval = bxattr_exit_ok;
812 free(current_xattr->value);
813 free(current_xattr->name);
817 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
818 jcr->last_fname, be.bstrerror());
819 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
820 jcr->last_fname, be.bstrerror());
821 free(current_xattr->value);
822 free(current_xattr->name);
828 * Store the actual length of the value.
830 current_xattr->value_length = xattr_value_len;
831 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
834 * Protect ourself against things getting out of hand.
836 if (expected_serialize_len >= MAX_XATTR_STREAM) {
837 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
838 jcr->last_fname, MAX_XATTR_STREAM);
839 free(current_xattr->value);
840 free(current_xattr->name);
846 xattr_value_list->append(current_xattr);
848 bp = strchr(bp, '\0') + 1;
853 xattr_list = (char *)NULL;
856 * If we found any xattr send them to the SD.
858 if (xattr_count > 0) {
860 * Serialize the datastream.
862 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
863 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
865 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
870 xattr_drop_internal_table(xattr_value_list);
873 * Send the datastream to the SD.
875 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
877 xattr_drop_internal_table(xattr_value_list);
879 return bxattr_exit_ok;
883 if (xattr_list != NULL) {
886 if (xattr_value_list != NULL) {
887 xattr_drop_internal_table(xattr_value_list);
892 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
894 xattr_t *current_xattr;
895 alist *xattr_value_list;
898 xattr_value_list = New(alist(10, not_owned_by_alist));
900 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
901 xattr_drop_internal_table(xattr_value_list);
902 return bxattr_exit_error;
905 foreach_alist(current_xattr, xattr_value_list) {
906 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
912 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
913 jcr->last_fname, be.bstrerror());
914 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
915 jcr->last_fname, be.bstrerror());
921 xattr_drop_internal_table(xattr_value_list);
922 return bxattr_exit_ok;
925 xattr_drop_internal_table(xattr_value_list);
926 return bxattr_exit_error;
930 * Function pointers to the build and parse function to use for these xattrs.
932 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
933 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
935 #elif defined(HAVE_FREEBSD_OS) || \
936 defined(HAVE_NETBSD_OS) || \
937 defined(HAVE_OPENBSD_OS)
939 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
940 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
941 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
942 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
943 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
944 #error "Missing full support for the extattr functions."
947 #ifdef HAVE_SYS_EXTATTR_H
948 #include <sys/extattr.h>
950 #error "Missing sys/extattr.h header file"
953 #ifdef HAVE_LIBUTIL_H
957 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
958 #define extattr_get_link extattr_get_file
960 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
961 #define extattr_set_link extattr_set_file
963 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
964 #define extattr_list_link extattr_list_file
967 #if defined(HAVE_FREEBSD_OS)
968 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
969 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
970 static const char *xattr_acl_skiplist[2] = { "system.posix1e.acl_access", NULL };
971 static const char *xattr_skiplist[1] = { NULL };
972 #elif defined(HAVE_NETBSD_OS)
973 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
974 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
975 static const char *xattr_acl_skiplist[1] = { NULL };
976 static const char *xattr_skiplist[1] = { NULL };
977 #elif defined(HAVE_OPENBSD_OS)
978 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
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 };
984 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
988 int cnt, index, xattr_count = 0;
989 int32_t xattr_list_len,
991 uint32_t expected_serialize_len = 0;
992 unsigned int namespace_index;
994 char *current_attrnamespace = NULL;
995 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
996 xattr_t *current_xattr;
997 alist *xattr_value_list = NULL;
998 bxattr_exit_code retval = bxattr_exit_error;
1001 xattr_value_list = New(alist(10, not_owned_by_alist));
1004 * Loop over all available xattr namespaces.
1006 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
1007 attrnamespace = os_default_xattr_namespaces[namespace_index];
1010 * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
1011 * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
1013 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1014 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
1015 attrnamespace, jcr->last_fname);
1016 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1017 attrnamespace, jcr->last_fname);
1022 * First get the length of the available list with extended attributes.
1023 * If we get EPERM on system namespace, don't return error.
1024 * This is expected for normal users trying to archive the system
1025 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1026 * they've decided to return EOPNOTSUPP instead.
1028 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1029 switch (xattr_list_len) {
1033 retval = bxattr_exit_ok;
1035 #if defined(EOPNOTSUPP)
1039 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1040 actuallyfree(current_attrnamespace);
1041 current_attrnamespace = NULL;
1048 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1049 jcr->last_fname, be.bstrerror());
1050 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1051 jcr->last_fname, be.bstrerror());
1062 * Allocate room for the extented attribute list.
1064 xattr_list = (char *)malloc(xattr_list_len + 1);
1065 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
1068 * Get the actual list of extended attributes names for a file.
1070 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
1071 switch (xattr_list_len) {
1075 retval = bxattr_exit_ok;
1078 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1079 jcr->last_fname, be.bstrerror());
1080 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1081 jcr->last_fname, be.bstrerror());
1088 xattr_list[xattr_list_len] = '\0';
1091 * Walk the list of extended attributes names and retrieve the data.
1092 * We already count the bytes needed for serializing the stream later on.
1094 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1098 * Print the current name into the buffer as its not null terminated we need to
1099 * use the length encoded in the string for copying only the needed bytes.
1101 cnt = xattr_list[index];
1102 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1103 cnt = ((int)sizeof(current_attrname) - 1);
1105 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1106 current_attrname[cnt] = '\0';
1109 * First make a xattr tuple of the current namespace and the name of the xattr.
1110 * e.g. something like user.<attrname> or system.<attrname>
1112 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
1115 * On some OSes you also get the acls in the extented attribute list.
1116 * So we check if we are already backing up acls and if we do we
1117 * don't store the extended attribute with the same info.
1119 if (ff_pkt->flags & FO_ACL) {
1120 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1121 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1129 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1132 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1133 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1145 * Each xattr valuepair starts with a magic so we can parse it easier.
1147 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1148 current_xattr->magic = XATTR_MAGIC;
1149 expected_serialize_len += sizeof(current_xattr->magic);
1152 * Allocate space for storing the name.
1154 current_xattr->name_length = strlen(current_attrtuple);
1155 current_xattr->name = (char *)malloc(current_xattr->name_length);
1156 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
1158 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1161 * First see how long the value is for the extended attribute.
1163 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
1164 switch (xattr_value_len) {
1168 retval = bxattr_exit_ok;
1169 free(current_xattr->name);
1170 free(current_xattr);
1173 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1174 jcr->last_fname, be.bstrerror());
1175 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1176 jcr->last_fname, be.bstrerror());
1177 free(current_xattr->name);
1178 free(current_xattr);
1183 current_xattr->value = NULL;
1184 current_xattr->value_length = 0;
1185 expected_serialize_len += sizeof(current_xattr->value_length);
1189 * Allocate space for storing the value.
1191 current_xattr->value = (char *)malloc(xattr_value_len);
1192 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1194 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
1195 if (xattr_value_len < 0) {
1198 retval = bxattr_exit_ok;
1199 free(current_xattr->value);
1200 free(current_xattr->name);
1201 free(current_xattr);
1204 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1205 jcr->last_fname, be.bstrerror());
1206 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1207 jcr->last_fname, be.bstrerror());
1208 free(current_xattr->value);
1209 free(current_xattr->name);
1210 free(current_xattr);
1216 * Store the actual length of the value.
1218 current_xattr->value_length = xattr_value_len;
1219 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1222 * Protect ourself against things getting out of hand.
1224 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1225 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1226 jcr->last_fname, MAX_XATTR_STREAM);
1227 free(current_xattr->value);
1228 free(current_xattr->name);
1229 free(current_xattr);
1235 xattr_value_list->append(current_xattr);
1241 * Drop the local copy of the current_attrnamespace.
1243 actuallyfree(current_attrnamespace);
1244 current_attrnamespace = NULL;
1247 * We are done with this xattr list.
1250 xattr_list = (char *)NULL;
1254 * If we found any xattr send them to the SD.
1256 if (xattr_count > 0) {
1258 * Serialize the datastream.
1260 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1261 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1263 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1268 xattr_drop_internal_table(xattr_value_list);
1271 * Send the datastream to the SD.
1273 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
1275 xattr_drop_internal_table(xattr_value_list);
1277 return bxattr_exit_ok;
1281 if (current_attrnamespace != NULL) {
1282 actuallyfree(current_attrnamespace);
1284 if (xattr_list != NULL) {
1287 if (xattr_value_list != NULL) {
1288 xattr_drop_internal_table(xattr_value_list);
1293 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
1295 xattr_t *current_xattr;
1296 alist *xattr_value_list;
1297 int current_attrnamespace, cnt;
1298 char *attrnamespace, *attrname;
1301 xattr_value_list = New(alist(10, not_owned_by_alist));
1303 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1304 xattr_drop_internal_table(xattr_value_list);
1305 return bxattr_exit_error;
1308 foreach_alist(current_xattr, xattr_value_list) {
1310 * Try splitting the xattr_name into a namespace and name part.
1311 * The splitting character is a .
1313 attrnamespace = current_xattr->name;
1314 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1315 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1316 current_xattr->name, jcr->last_fname);
1317 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1318 current_xattr->name, jcr->last_fname);
1324 * Make sure the attrnamespace makes sense.
1326 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1327 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1328 attrnamespace, jcr->last_fname);
1329 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1330 attrnamespace, jcr->last_fname);
1335 * Try restoring the extended attribute.
1337 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1338 attrname, current_xattr->value, current_xattr->value_length);
1339 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1345 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1346 jcr->last_fname, be.bstrerror());
1347 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1348 jcr->last_fname, be.bstrerror());
1355 xattr_drop_internal_table(xattr_value_list);
1356 return bxattr_exit_ok;
1359 xattr_drop_internal_table(xattr_value_list);
1360 return bxattr_exit_error;
1364 * Function pointers to the build and parse function to use for these xattrs.
1366 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1367 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1369 #elif defined(HAVE_TRU64_OS)
1371 #if !defined(HAVE_GETPROPLIST) || \
1372 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1373 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1374 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1375 !defined(HAVE_SETPROPLIST)
1376 #error "Missing full support for the Extended Attributes functions."
1379 #ifdef HAVE_SYS_PROPLIST_H
1380 #include <sys/proplist.h>
1382 #error "Missing sys/proplist.h header file"
1386 * Define the supported XATTR streams for this OS
1388 static int os_default_xattr_streams[1] = { STREAM_XATTR_TRU64 };
1389 static const char *xattr_acl_skiplist[1] = { NULL };
1390 static const char *xattr_skiplist[1] = { NULL };
1392 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1397 int xattr_count = 0;
1400 int32_t xattr_list_len,
1403 uint32_t expected_serialize_len = 0;
1404 xattr_t *current_xattr;
1405 alist *xattr_value_list = NULL;
1406 struct proplistname_args prop_args;
1407 bxattr_exit_code retval = bxattr_exit_error;
1408 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1411 xattrbuf_size = sizeof_pool_memory(xattrbuf);
1412 xattrbuf_min_size = 0;
1413 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1414 xattrbuf, &xattrbuf_min_size);
1417 * See what xattr are available.
1419 switch (xattr_list_len) {
1423 retval = bacl_exit_ok;
1426 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1427 jcr->last_fname, be.bstrerror());
1428 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1429 jcr->last_fname, be.bstrerror());
1434 if (xattrbuf_min_size) {
1436 * The buffer isn't big enough to hold the xattr data, we now have
1437 * a minimum buffersize so we resize the buffer and try again.
1439 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1440 xattrbuf_size = xattrbuf_min_size + 1;
1441 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1442 xattrbuf, &xattrbuf_min_size);
1443 switch (xattr_list_len) {
1447 retval = bacl_exit_ok;
1450 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1451 jcr->last_fname, be.bstrerror());
1452 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1453 jcr->last_fname, be.bstrerror());
1459 * This should never happen as we sized the buffer according to the minimumsize
1460 * returned by a previous getproplist call. If it does happen things are fishy and
1461 * we are better of forgetting this xattr as it seems its list is changing at this
1462 * exact moment so we can never make a good backup copy of it.
1464 retval = bacl_exit_ok;
1473 retval = bacl_exit_ok;
1481 xattr_value_list = New(alist(10, not_owned_by_alist));
1484 * Walk the list of extended attributes names and retrieve the data.
1485 * We already count the bytes needed for serializing the stream later on.
1488 while (xattrbuf_size > 0) {
1490 * Call getproplist_entry to initialize name and value
1491 * pointers to entries position within buffer.
1493 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
1496 * On some OSes you also get the acls in the extented attribute list.
1497 * So we check if we are already backing up acls and if we do we
1498 * don't store the extended attribute with the same info.
1500 if (ff_pkt->flags & FO_ACL) {
1501 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1502 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
1510 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1513 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1514 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
1526 * Each xattr valuepair starts with a magic so we can parse it easier.
1528 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1529 current_xattr->magic = XATTR_MAGIC;
1530 expected_serialize_len += sizeof(current_xattr->magic);
1532 current_xattr->name_length = strlen(xattr_name);
1533 current_xattr->name = bstrdup(xattr_name);
1535 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1537 current_xattr->value_length = *xattr_value_len;
1538 current_xattr->value = (char *)malloc(current_xattr->value_length);
1539 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
1541 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1544 * Protect ourself against things getting out of hand.
1546 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1547 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1548 jcr->last_fname, MAX_XATTR_STREAM);
1549 free(current_xattr->value);
1550 free(current_xattr->name);
1551 free(current_xattr);
1555 xattr_value_list->append(current_xattr);
1560 * If we found any xattr send them to the SD.
1562 if (xattr_count > 0) {
1564 * Serialize the datastream.
1566 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1567 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1569 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1575 * Send the datastream to the SD.
1577 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1581 if (xattr_value_list != NULL) {
1582 xattr_drop_internal_table(xattr_value_list);
1584 free_pool_memory(xattrbuf);
1589 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr, int stream)
1591 char *bp, *xattrbuf;
1592 int32_t xattrbuf_size, cnt;
1593 xattr_t *current_xattr;
1594 alist *xattr_value_list;
1597 xattr_value_list = New(alist(10, not_owned_by_alist));
1599 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1600 xattr_drop_internal_table(xattr_value_list);
1601 return bxattr_exit_error;
1605 * See how big the propertylist must be.
1608 foreach_alist(current_xattr, xattr_value_list) {
1609 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
1612 xattrbuf = (char *)malloc(xattrbuf_size);
1617 * Add all value pairs to the proplist.
1619 foreach_alist(current_xattr, xattr_value_list) {
1620 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
1621 current_xattr->value, &bp);
1624 if (cnt != xattrbuf_size) {
1625 Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
1627 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
1634 * Restore the list of extended attributes on the file.
1636 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
1641 retval = bacl_exit_ok;
1645 Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
1646 jcr->last_fname, be.bstrerror());
1647 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
1648 jcr->last_fname, be.bstrerror());
1659 xattr_drop_internal_table(xattr_value_list);
1660 return bxattr_exit_ok;
1663 xattr_drop_internal_table(xattr_value_list);
1664 return bxattr_exit_error;
1668 * Function pointers to the build and parse function to use for these xattrs.
1670 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_xattr_streams;
1671 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = tru64_parse_xattr_streams;
1673 #elif defined(HAVE_SUN_OS)
1675 * Solaris extended attributes were introduced in Solaris 9
1678 * Solaris extensible attributes were introduced in OpenSolaris
1679 * by PSARC 2007/315 Solaris extensible attributes are also
1680 * sometimes called extended system attributes.
1682 * man fsattr(5) on Solaris gives a wealth of info. The most
1683 * important bits are:
1685 * Attributes are logically supported as files within the file
1686 * system. The file system is therefore augmented with an
1687 * orthogonal name space of file attributes. Any file (includ-
1688 * ing attribute files) can have an arbitrarily deep attribute
1689 * tree associated with it. Attribute values are accessed by
1690 * file descriptors obtained through a special attribute inter-
1691 * face. This logical view of "attributes as files" allows the
1692 * leveraging of existing file system interface functionality
1693 * to support the construction, deletion, and manipulation of
1696 * The special files "." and ".." retain their accustomed
1697 * semantics within the attribute hierarchy. The "." attribute
1698 * file refers to the current directory and the ".." attribute
1699 * file refers to the parent directory. The unnamed directory
1700 * at the head of each attribute tree is considered the "child"
1701 * of the file it is associated with and the ".." file refers
1702 * to the associated file. For any non-directory file with
1703 * attributes, the ".." entry in the unnamed directory refers
1704 * to a file that is not a directory.
1706 * Conceptually, the attribute model is fully general. Extended
1707 * attributes can be any type of file (doors, links, direc-
1708 * tories, and so forth) and can even have their own attributes
1709 * (fully recursive). As a result, the attributes associated
1710 * with a file could be an arbitrarily deep directory hierarchy
1711 * where each attribute could have an equally complex attribute
1712 * tree associated with it. Not all implementations are able
1713 * to, or want to, support the full model. Implementation are
1714 * therefore permitted to reject operations that are not sup-
1715 * ported. For example, the implementation for the UFS file
1716 * system allows only regular files as attributes (for example,
1717 * no sub-directories) and rejects attempts to place attributes
1720 * The following list details the operations that are rejected
1721 * in the current implementation:
1723 * link Any attempt to create links between
1724 * attribute and non-attribute space
1725 * is rejected to prevent security-
1726 * related or otherwise sensitive
1727 * attributes from being exposed, and
1728 * therefore manipulable, as regular
1731 * rename Any attempt to rename between
1732 * attribute and non-attribute space
1733 * is rejected to prevent an already
1734 * linked file from being renamed and
1735 * thereby circumventing the link res-
1738 * mkdir, symlink, mknod Any attempt to create a "non-
1739 * regular" file in attribute space is
1740 * rejected to reduce the functional-
1741 * ity, and therefore exposure and
1742 * risk, of the initial implementa-
1745 * The entire available name space has been allocated to "gen-
1746 * eral use" to bring the implementation in line with the NFSv4
1747 * draft standard [NFSv4]. That standard defines "named attri-
1748 * butes" (equivalent to Solaris Extended Attributes) with no
1749 * naming restrictions. All Sun applications making use of
1750 * opaque extended attributes will use the prefix "SUNW".
1753 #ifdef HAVE_SYS_ATTR_H
1754 #include <sys/attr.h>
1761 #ifdef HAVE_SYS_NVPAIR_H
1762 #include <sys/nvpair.h>
1765 #ifdef HAVE_SYS_ACL_H
1766 #include <sys/acl.h>
1769 #if !defined(HAVE_OPENAT) || \
1770 !defined(HAVE_UNLINKAT) || \
1771 !defined(HAVE_FCHOWNAT) || \
1772 !defined(HAVE_FUTIMESAT)
1773 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
1777 * Define the supported XATTR streams for this OS
1779 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1780 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
1782 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
1783 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
1786 * This code creates a temporary cache with entries for each xattr which has
1787 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
1789 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
1791 xattr_link_cache_entry_t *ptr;
1793 foreach_alist(ptr, jcr->xattr_data->link_cache) {
1794 if (ptr && ptr->inum == inum) {
1801 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
1803 xattr_link_cache_entry_t *ptr;
1805 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
1806 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
1808 bstrncpy(ptr->target, target, sizeof(ptr->target));
1809 jcr->xattr_data->link_cache->append(ptr);
1812 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1814 * This function returns true if a non default extended system attribute
1815 * list is associated with fd and returns false when an error has occured
1816 * or when only extended system attributes other than archive,
1817 * av_modified or crtime are set.
1819 * The function returns true for the following cases:
1821 * - any extended system attribute other than the default attributes
1822 * ('archive', 'av_modified' and 'crtime') is set
1823 * - nvlist has NULL name string
1824 * - nvpair has data type of 'nvlist'
1825 * - default data type.
1827 static bool solaris_has_non_transient_extensible_attributes(int fd)
1835 bool retval = false;
1837 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
1842 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
1843 name = nvpair_name(pair);
1846 fattr = name_to_attr(name);
1852 type = nvpair_type(pair);
1854 case DATA_TYPE_BOOLEAN_VALUE:
1855 if (nvpair_value_boolean_value(pair, &value) != 0) {
1858 if (value && fattr != F_ARCHIVE &&
1859 fattr != F_AV_MODIFIED) {
1864 case DATA_TYPE_UINT64_ARRAY:
1865 if (fattr != F_CRTIME) {
1870 case DATA_TYPE_NVLIST:
1878 if (response != NULL) {
1879 nvlist_free(response);
1883 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1885 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
1887 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1888 * There is no need to store those acls as we already store the stat bits too.
1890 static bool acl_is_trivial(int count, aclent_t *entries)
1895 for (n = 0; n < count; n++) {
1897 if (!(ace->a_type == USER_OBJ ||
1898 ace->a_type == GROUP_OBJ ||
1899 ace->a_type == OTHER_OBJ ||
1900 ace->a_type == CLASS_OBJ))
1905 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
1907 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
1910 #ifdef HAVE_EXTENDED_ACL
1916 * See if this attribute has an ACL
1918 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
1919 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
1921 * See if there is a non trivial acl on the file.
1923 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
1924 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
1927 return bxattr_exit_ok;
1929 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1930 attrname, jcr->last_fname, be.bstrerror());
1931 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
1932 attrname, jcr->last_fname, be.bstrerror());
1933 return bxattr_exit_error;
1938 #if defined(ACL_SID_FMT)
1940 * New format flag added in newer Solaris versions.
1942 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1944 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1945 #endif /* ACL_SID_FMT */
1947 *acl_text = acl_totext(aclp, flags);
1955 return bxattr_exit_ok;
1956 #else /* HAVE_EXTENDED_ACL */
1958 aclent_t *acls = NULL;
1962 * See if this attribute has an ACL
1965 n = facl(fd, GETACLCNT, 0, NULL);
1967 n = acl(attrname, GETACLCNT, 0, NULL);
1970 if (n >= MIN_ACL_ENTRIES) {
1971 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1972 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
1973 acl(attrname, GETACL, n, acls) != n) {
1977 return bxattr_exit_ok;
1979 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1980 attrname, jcr->last_fname, be.bstrerror());
1981 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
1982 attrname, jcr->last_fname, be.bstrerror());
1984 return bxattr_exit_error;
1989 * See if there is a non trivial acl on the file.
1991 if (!acl_is_trivial(n, acls)) {
1992 if ((*acl_text = acltotext(acls, n)) == NULL) {
1993 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
1994 attrname, jcr->last_fname, be.bstrerror());
1995 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
1996 attrname, jcr->last_fname, be.bstrerror());
1998 return bxattr_exit_error;
2008 return bxattr_exit_ok;
2009 #endif /* HAVE_EXTENDED_ACL */
2011 #else /* HAVE_ACL */
2012 return bxattr_exit_ok;
2013 #endif /* HAVE_ACL */
2017 * Forward declaration for recursive function call.
2019 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2022 * Save an extended or extensible attribute.
2023 * This is stored as an opaque stream of bytes with the following encoding:
2025 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2027 * or for a hardlinked or symlinked attribute
2029 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2031 * xattr_name can be a subpath relative to the file the xattr is on.
2032 * stat_buffer is the string representation of the stat struct.
2033 * acl_string is an acl text when a non trivial acl is set on the xattr.
2034 * actual_xattr_data is the content of the xattr file.
2036 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2037 const char *attrname, bool toplevel_hidden_dir, int stream)
2042 xattr_link_cache_entry_t *xlce;
2043 char target_attrname[PATH_MAX];
2044 char link_source[PATH_MAX];
2045 char *acl_text = NULL;
2046 char attribs[MAXSTRING];
2047 char buffer[XATTR_BUFSIZ];
2048 bxattr_exit_code retval = bxattr_exit_error;
2051 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2054 * Get the stats of the extended or extensible attribute.
2056 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2059 retval = bxattr_exit_ok;
2062 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2063 target_attrname, jcr->last_fname, be.bstrerror());
2064 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2065 target_attrname, jcr->last_fname, be.bstrerror());
2071 * Based on the filetype perform the correct action. We support most filetypes here, more
2072 * then the actual implementation on Solaris supports so some code may never get executed
2073 * due to limitations in the implementation.
2075 switch (st.st_mode & S_IFMT) {
2080 * Get any acl on the xattr.
2082 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2086 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2087 * Encode the stat struct into an ASCII representation.
2089 encode_stat(attribs, &st, 0, stream);
2090 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2091 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2095 * Get any acl on the xattr.
2097 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2101 * See if this is the toplevel_hidden_dir being saved.
2103 if (toplevel_hidden_dir) {
2105 * Save the data for later storage when we encounter a real xattr. We store the data
2106 * in the jcr->xattr_data->content buffer and flush that just before sending out the
2107 * first real xattr. Encode the stat struct into an ASCII representation and jump
2108 * out of the function.
2110 encode_stat(attribs, &st, 0, stream);
2111 cnt = bsnprintf(buffer, sizeof(buffer),
2113 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2114 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2115 jcr->xattr_data->content_length = cnt;
2119 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2120 * Encode the stat struct into an ASCII representation.
2122 encode_stat(attribs, &st, 0, stream);
2123 cnt = bsnprintf(buffer, sizeof(buffer),
2125 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2130 * If this is a hardlinked file check the inode cache for a hit.
2132 if (st.st_nlink > 1) {
2134 * See if the cache already knows this inode number.
2136 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2138 * Generate a xattr encoding with the reference to the target in there.
2140 encode_stat(attribs, &st, st.st_ino, stream);
2141 cnt = bsnprintf(buffer, sizeof(buffer),
2143 target_attrname, 0, attribs, 0, xlce->target, 0);
2144 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2145 jcr->xattr_data->content_length = cnt;
2146 retval = send_xattr_stream(jcr, stream);
2149 * For a hard linked file we are ready now, no need to recursively save the attributes.
2155 * Store this hard linked file in the cache.
2156 * Store the name relative to the top level xattr space.
2158 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2162 * Get any acl on the xattr.
2164 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2169 * Encode the stat struct into an ASCII representation.
2171 encode_stat(attribs, &st, 0, stream);
2172 cnt = bsnprintf(buffer, sizeof(buffer),
2174 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2177 * Open the extended or extensible attribute file.
2179 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2182 retval = bxattr_exit_ok;
2185 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2186 target_attrname, jcr->last_fname, be.bstrerror());
2187 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2188 target_attrname, jcr->last_fname, be.bstrerror());
2195 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2196 * Encode the stat struct into an ASCII representation.
2198 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2201 retval = bxattr_exit_ok;
2204 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2205 target_attrname, jcr->last_fname, be.bstrerror());
2206 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2207 target_attrname, jcr->last_fname, be.bstrerror());
2213 * Generate a xattr encoding with the reference to the target in there.
2215 encode_stat(attribs, &st, st.st_ino, stream);
2216 cnt = bsnprintf(buffer, sizeof(buffer),
2218 target_attrname, 0, attribs, 0, link_source, 0);
2219 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2220 jcr->xattr_data->content_length = cnt;
2221 retval = send_xattr_stream(jcr, stream);
2223 if (retval == bxattr_exit_ok) {
2224 jcr->xattr_data->nr_saved++;
2228 * For a soft linked file we are ready now, no need to recursively save the attributes.
2236 * See if this is the first real xattr being saved.
2237 * If it is save the toplevel_hidden_dir attributes first.
2238 * This is easy as its stored already in the jcr->xattr_data->content buffer.
2240 if (jcr->xattr_data->nr_saved == 0) {
2241 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2242 if (retval != bxattr_exit_ok) {
2245 jcr->xattr_data->nr_saved++;
2248 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2249 jcr->xattr_data->content_length = cnt;
2252 * Only dump the content of regular files.
2254 switch (st.st_mode & S_IFMT) {
2256 if (st.st_size > 0) {
2258 * Protect ourself against things getting out of hand.
2260 if (st.st_size >= MAX_XATTR_STREAM) {
2261 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2262 jcr->last_fname, MAX_XATTR_STREAM);
2266 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2267 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
2268 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
2269 jcr->xattr_data->content_length += cnt;
2273 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
2274 target_attrname, jcr->last_fname);
2275 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2276 target_attrname, jcr->last_fname);
2287 retval = send_xattr_stream(jcr, stream);
2288 if (retval == bxattr_exit_ok) {
2289 jcr->xattr_data->nr_saved++;
2294 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2295 * available on this extended attribute.
2298 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2301 * The recursive call could change our working dir so change back to the wanted workdir.
2303 if (fchdir(fd) < 0) {
2306 retval = bxattr_exit_ok;
2309 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2310 jcr->last_fname, be.bstrerror());
2311 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2312 jcr->last_fname, fd, be.bstrerror());
2319 if (acl_text != NULL) {
2328 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2331 int fd, filefd = -1, attrdirfd = -1;
2334 char current_xattr_namespace[PATH_MAX];
2335 bxattr_exit_code retval = bxattr_exit_error;
2339 * Determine what argument to use. Use attr_parent when set
2340 * (recursive call) or jcr->last_fname for first call. Also save
2341 * the current depth of the xattr_space we are in.
2345 if (xattr_namespace) {
2346 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2347 xattr_namespace, attr_parent);
2349 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2352 name = jcr->last_fname;
2353 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2357 * Open the file on which to save the xattrs read-only.
2359 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2362 retval = bxattr_exit_ok;
2365 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2366 jcr->last_fname, be.bstrerror());
2367 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2368 jcr->last_fname, be.bstrerror());
2374 * Open the xattr naming space.
2376 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2380 * Gentile way of the system saying this type of xattr layering is not supported.
2381 * Which is not problem we just forget about this this xattr.
2382 * But as this is not an error we return a positive return value.
2384 retval = bxattr_exit_ok;
2387 retval = bxattr_exit_ok;
2390 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2391 name, jcr->last_fname, be.bstrerror());
2392 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2393 name, jcr->last_fname, be.bstrerror());
2399 * We need to change into the attribute directory to determine if each of the
2400 * attributes should be saved.
2402 if (fchdir(attrdirfd) < 0) {
2403 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2404 jcr->last_fname, be.bstrerror());
2405 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2406 jcr->last_fname, attrdirfd, be.bstrerror());
2411 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2412 * else because the readdir returns "." entry after the extensible attr entry.
2413 * And as we want this entry before anything else we better just save its data.
2416 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2417 true, STREAM_XATTR_SOLARIS);
2419 if ((fd = dup(attrdirfd)) == -1 ||
2420 (dirp = fdopendir(fd)) == (DIR *)NULL) {
2421 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2422 jcr->last_fname, be.bstrerror());
2423 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
2424 jcr->last_fname, fd, be.bstrerror());
2430 * Walk the namespace.
2432 while ((dp = readdir(dirp)) != NULL) {
2434 * Skip only the toplevel . dir.
2436 if (!attr_parent && bstrcmp(dp->d_name, "."))
2440 * Skip all .. directories
2442 if (bstrcmp(dp->d_name, ".."))
2445 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2446 current_xattr_namespace, dp->d_name, jcr->last_fname);
2448 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2450 * We are not interested in read-only extensible attributes.
2452 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2453 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2454 current_xattr_namespace, dp->d_name, jcr->last_fname);
2460 * We are only interested in read-write extensible attributes
2461 * when they contain non-transient values.
2463 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2465 * Determine if there are non-transient system attributes at the toplevel.
2466 * We need to provide a fd to the open file.
2468 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2469 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2470 current_xattr_namespace, dp->d_name, jcr->last_fname);
2477 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2478 false, STREAM_XATTR_SOLARIS_SYS);
2481 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2486 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2487 false, STREAM_XATTR_SOLARIS);
2491 retval = bxattr_exit_ok;
2494 if (attrdirfd != -1)
2502 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
2504 #ifdef HAVE_EXTENDED_ACL
2509 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
2510 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
2512 return bxattr_exit_error;
2515 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
2516 acl_set(attrname, aclp) != 0) {
2517 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2518 attrname, jcr->last_fname, be.bstrerror());
2519 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2520 attrname, jcr->last_fname, be.bstrerror());
2521 return bxattr_exit_error;
2527 return bxattr_exit_ok;
2529 #else /* HAVE_EXTENDED_ACL */
2531 aclent_t *acls = NULL;
2534 acls = aclfromtext(acl_text, &n);
2536 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
2537 acl(attrname, SETACL, n, acls) != 0) {
2538 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2539 attrname, jcr->last_fname, be.bstrerror());
2540 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2541 attrname, jcr->last_fname, be.bstrerror());
2542 return bxattr_exit_error;
2549 return bxattr_exit_ok;
2551 #endif /* HAVE_EXTENDED_ACL */
2554 #endif /* HAVE_ACL */
2556 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
2558 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
2559 int used_bytes, total_bytes, cnt;
2560 char *bp, *target_attrname, *attribs;
2561 char *linked_target = NULL;
2562 char *acl_text = NULL;
2566 struct timeval times[2];
2567 bxattr_exit_code retval = bxattr_exit_error;
2571 * Parse the xattr stream. First the part that is the same for all xattrs.
2574 total_bytes = jcr->xattr_data->content_length;
2577 * The name of the target xattr has a leading / we are not interested
2578 * in that so skip it when decoding the string. We always start a the /
2579 * of the xattr space anyway.
2581 target_attrname = jcr->xattr_data->content + 1;
2582 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
2583 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2589 * Open the file on which to restore the xattrs read-only.
2591 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
2592 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2593 jcr->last_fname, be.bstrerror());
2594 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2595 jcr->last_fname, be.bstrerror());
2600 * Open the xattr naming space and make it the current working dir.
2602 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2603 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
2604 jcr->last_fname, be.bstrerror());
2605 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
2606 jcr->last_fname, be.bstrerror());
2610 if (fchdir(attrdirfd) < 0) {
2611 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2612 jcr->last_fname, be.bstrerror());
2613 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2614 jcr->last_fname, attrdirfd, be.bstrerror());
2619 * Try to open the correct xattr subdir based on the target_attrname given.
2620 * e.g. check if its a subdir attrname. Each / in the string makes us go
2623 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2626 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2627 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2628 target_attrname, jcr->last_fname, be.bstrerror());
2629 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2630 target_attrname, jcr->last_fname, be.bstrerror());
2638 * Open the xattr naming space.
2640 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2641 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2642 target_attrname, jcr->last_fname, be.bstrerror());
2643 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2644 target_attrname, jcr->last_fname, be.bstrerror());
2652 * Make the xattr space our current workingdir.
2654 if (fchdir(attrdirfd) < 0) {
2655 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2656 target_attrname, jcr->last_fname, be.bstrerror());
2657 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2658 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2662 target_attrname = ++bp;
2666 * Decode the attributes from the stream.
2668 decode_stat(attribs, &st, &inum);
2671 * Decode the next field (acl_text).
2673 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2674 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2680 * Based on the filetype perform the correct action. We support most filetypes here, more
2681 * then the actual implementation on Solaris supports so some code may never get executed
2682 * due to limitations in the implementation.
2684 switch (st.st_mode & S_IFMT) {
2687 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2689 unlinkat(attrdirfd, target_attrname, 0);
2690 if (mkfifo(target_attrname, st.st_mode) < 0) {
2691 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
2692 target_attrname, jcr->last_fname, be.bstrerror());
2693 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
2694 target_attrname, jcr->last_fname, be.bstrerror());
2701 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2703 unlinkat(attrdirfd, target_attrname, 0);
2704 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
2705 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
2706 target_attrname, jcr->last_fname, be.bstrerror());
2707 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
2708 target_attrname, jcr->last_fname, be.bstrerror());
2714 * If its not the hidden_dir create the entry.
2715 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2717 if (!bstrcmp(target_attrname, ".")) {
2718 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
2719 if (mkdir(target_attrname, st.st_mode) < 0) {
2720 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
2721 target_attrname, jcr->last_fname, be.bstrerror());
2722 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
2723 target_attrname, jcr->last_fname, be.bstrerror());
2730 * See if this is a hard linked file. e.g. inum != 0
2735 unlinkat(attrdirfd, target_attrname, 0);
2736 if (link(linked_target, target_attrname) < 0) {
2737 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
2738 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2739 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
2740 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2745 * Successfully restored xattr.
2747 retval = bxattr_exit_ok;
2750 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
2751 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
2755 if (used_bytes < (total_bytes - 1))
2759 * Restore the actual xattr.
2761 if (!is_extensible) {
2762 unlinkat(attrdirfd, target_attrname, 0);
2765 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
2766 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2767 target_attrname, jcr->last_fname, be.bstrerror());
2768 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2769 target_attrname, jcr->last_fname, be.bstrerror());
2775 * Restore the actual data.
2777 if (st.st_size > 0) {
2778 used_bytes = (data - jcr->xattr_data->content);
2779 cnt = total_bytes - used_bytes;
2782 * Do a sanity check, the st.st_size should be the same as the number of bytes
2783 * we have available as data of the stream.
2785 if (cnt != st.st_size) {
2786 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
2787 target_attrname, jcr->last_fname);
2788 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
2789 target_attrname, jcr->last_fname);
2794 cnt = write(attrfd, data, cnt);
2796 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
2797 target_attrname, jcr->last_fname, be.bstrerror());
2798 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
2799 target_attrname, jcr->last_fname, be.bstrerror());
2805 cnt = total_bytes - used_bytes;
2811 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2815 if (symlink(linked_target, target_attrname) < 0) {
2816 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
2817 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2818 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
2819 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2824 * Successfully restored xattr.
2826 retval = bxattr_exit_ok;
2833 * Restore owner and acl for non extensible attributes.
2835 if (!is_extensible) {
2836 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
2840 * Gentile way of the system saying this type of xattr layering is not supported.
2841 * But as this is not an error we return a positive return value.
2843 retval = bxattr_exit_ok;
2846 retval = bxattr_exit_ok;
2849 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
2850 target_attrname, jcr->last_fname, be.bstrerror());
2851 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
2852 target_attrname, jcr->last_fname, be.bstrerror());
2859 if (acl_text && *acl_text)
2860 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
2862 #endif /* HAVE_ACL */
2865 * For a non extensible attribute restore access and modification time on the xattr.
2867 if (!is_extensible) {
2868 times[0].tv_sec = st.st_atime;
2869 times[0].tv_usec = 0;
2870 times[1].tv_sec = st.st_mtime;
2871 times[1].tv_usec = 0;
2873 if (futimesat(attrdirfd, target_attrname, times) < 0) {
2874 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
2875 target_attrname, jcr->last_fname, be.bstrerror());
2876 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
2877 target_attrname, jcr->last_fname, be.bstrerror());
2883 * Successfully restored xattr.
2885 retval = bxattr_exit_ok;
2889 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
2891 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
2898 if (attrdirfd != -1) {
2907 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2910 bxattr_exit_code retval = bxattr_exit_ok;
2913 * First see if extended attributes or extensible attributes are present.
2914 * If not just pretend things went ok.
2916 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
2917 jcr->xattr_data->nr_saved = 0;
2918 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
2921 * As we change the cwd in the save function save the current cwd
2922 * for restore after return from the solaris_save_xattrs function.
2924 getcwd(cwd, sizeof(cwd));
2925 retval = solaris_save_xattrs(jcr, NULL, NULL);
2927 delete jcr->xattr_data->link_cache;
2928 jcr->xattr_data->link_cache = NULL;
2933 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
2936 bool is_extensible = false;
2937 bxattr_exit_code retval;
2940 * First make sure we can restore xattr on the filesystem.
2943 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2944 case STREAM_XATTR_SOLARIS_SYS:
2945 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
2946 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
2947 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
2949 return bxattr_exit_error;
2952 is_extensible = true;
2955 case STREAM_XATTR_SOLARIS:
2956 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
2957 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
2958 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
2960 return bxattr_exit_error;
2964 return bxattr_exit_error;
2968 * As we change the cwd in the restore function save the current cwd
2969 * for restore after return from the solaris_restore_xattrs function.
2971 getcwd(cwd, sizeof(cwd));
2972 retval = solaris_restore_xattrs(jcr, is_extensible);
2979 * Function pointers to the build and parse function to use for these xattrs.
2981 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
2982 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
2984 #endif /* defined(HAVE_SUN_OS) */
2987 * Entry points when compiled with support for XATTRs on a supported platform.
2989 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2991 if (os_build_xattr_streams) {
2992 return (*os_build_xattr_streams)(jcr, ff_pkt);
2994 return bxattr_exit_error;
2997 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
3001 if (os_parse_xattr_streams) {
3003 * See if we can parse this stream, and ifso give it a try.
3005 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3006 if (os_default_xattr_streams[cnt] == stream) {
3007 return (*os_parse_xattr_streams)(jcr, stream);
3012 * Issue a warning and discard the message. But pretend the restore was ok.
3014 Jmsg2(jcr, M_WARNING, 0,
3015 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3016 jcr->last_fname, stream);
3017 return bxattr_exit_error;