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)
1398 int xattr_count = 0;
1401 int32_t xattr_list_len,
1404 uint32_t expected_serialize_len = 0;
1405 xattr_t *current_xattr;
1406 alist *xattr_value_list = NULL;
1407 struct proplistname_args prop_args;
1408 bxattr_exit_code retval = bxattr_exit_error;
1409 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1412 xattrbuf_size = sizeof_pool_memory(xattrbuf);
1413 xattrbuf_min_size = 0;
1414 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1415 xattrbuf, &xattrbuf_min_size);
1418 * See what xattr are available.
1420 switch (xattr_list_len) {
1424 retval = bacl_exit_ok;
1427 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1428 jcr->last_fname, be.bstrerror());
1429 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1430 jcr->last_fname, be.bstrerror());
1435 if (xattrbuf_min_size) {
1437 * The buffer isn't big enough to hold the xattr data, we now have
1438 * a minimum buffersize so we resize the buffer and try again.
1440 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1441 xattrbuf_size = xattrbuf_min_size + 1;
1442 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1443 xattrbuf, &xattrbuf_min_size);
1444 switch (xattr_list_len) {
1448 retval = bacl_exit_ok;
1451 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1452 jcr->last_fname, be.bstrerror());
1453 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1454 jcr->last_fname, be.bstrerror());
1460 * This should never happen as we sized the buffer according to the minimumsize
1461 * returned by a previous getproplist call. If it does happen things are fishy and
1462 * we are better of forgetting this xattr as it seems its list is changing at this
1463 * exact moment so we can never make a good backup copy of it.
1465 retval = bacl_exit_ok;
1474 retval = bacl_exit_ok;
1482 xattr_value_list = New(alist(10, not_owned_by_alist));
1485 * Walk the list of extended attributes names and retrieve the data.
1486 * We already count the bytes needed for serializing the stream later on.
1489 while (xattrbuf_size > 0) {
1491 * Call getproplist_entry to initialize name and value
1492 * pointers to entries position within buffer.
1494 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
1497 * On some OSes you also get the acls in the extented attribute list.
1498 * So we check if we are already backing up acls and if we do we
1499 * don't store the extended attribute with the same info.
1501 if (ff_pkt->flags & FO_ACL) {
1502 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1503 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
1511 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1514 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1515 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
1527 * Each xattr valuepair starts with a magic so we can parse it easier.
1529 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1530 current_xattr->magic = XATTR_MAGIC;
1531 expected_serialize_len += sizeof(current_xattr->magic);
1533 current_xattr->name_length = strlen(xattr_name);
1534 current_xattr->name = bstrdup(xattr_name);
1536 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1538 current_xattr->value_length = *xattr_value_len;
1539 current_xattr->value = (char *)malloc(current_xattr->value_length);
1540 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
1542 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1545 * Protect ourself against things getting out of hand.
1547 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1548 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1549 jcr->last_fname, MAX_XATTR_STREAM);
1550 free(current_xattr->value);
1551 free(current_xattr->name);
1552 free(current_xattr);
1556 xattr_value_list->append(current_xattr);
1561 * If we found any xattr send them to the SD.
1563 if (xattr_count > 0) {
1565 * Serialize the datastream.
1567 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1568 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1570 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1576 * Send the datastream to the SD.
1578 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1582 if (xattr_value_list != NULL) {
1583 xattr_drop_internal_table(xattr_value_list);
1585 free_pool_memory(xattrbuf);
1590 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr, int stream)
1592 char *bp, *xattrbuf = NULL;
1593 int32_t xattrbuf_size, cnt;
1594 xattr_t *current_xattr;
1595 alist *xattr_value_list;
1598 xattr_value_list = New(alist(10, not_owned_by_alist));
1600 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1601 xattr_drop_internal_table(xattr_value_list);
1602 return bxattr_exit_error;
1606 * See how big the propertylist must be.
1609 foreach_alist(current_xattr, xattr_value_list) {
1610 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
1613 xattrbuf = (char *)malloc(xattrbuf_size);
1616 * Add all value pairs to the proplist.
1620 foreach_alist(current_xattr, xattr_value_list) {
1621 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
1622 current_xattr->value, &bp);
1628 if (cnt != xattrbuf_size) {
1629 Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
1631 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
1637 * Restore the list of extended attributes on the file.
1639 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
1644 retval = bacl_exit_ok;
1647 Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
1648 jcr->last_fname, be.bstrerror());
1649 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
1650 jcr->last_fname, be.bstrerror());
1660 xattr_drop_internal_table(xattr_value_list);
1661 return bxattr_exit_ok;
1667 xattr_drop_internal_table(xattr_value_list);
1668 return bxattr_exit_error;
1672 * Function pointers to the build and parse function to use for these xattrs.
1674 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_xattr_streams;
1675 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = tru64_parse_xattr_streams;
1677 #elif defined(HAVE_SUN_OS)
1679 * Solaris extended attributes were introduced in Solaris 9
1682 * Solaris extensible attributes were introduced in OpenSolaris
1683 * by PSARC 2007/315 Solaris extensible attributes are also
1684 * sometimes called extended system attributes.
1686 * man fsattr(5) on Solaris gives a wealth of info. The most
1687 * important bits are:
1689 * Attributes are logically supported as files within the file
1690 * system. The file system is therefore augmented with an
1691 * orthogonal name space of file attributes. Any file (includ-
1692 * ing attribute files) can have an arbitrarily deep attribute
1693 * tree associated with it. Attribute values are accessed by
1694 * file descriptors obtained through a special attribute inter-
1695 * face. This logical view of "attributes as files" allows the
1696 * leveraging of existing file system interface functionality
1697 * to support the construction, deletion, and manipulation of
1700 * The special files "." and ".." retain their accustomed
1701 * semantics within the attribute hierarchy. The "." attribute
1702 * file refers to the current directory and the ".." attribute
1703 * file refers to the parent directory. The unnamed directory
1704 * at the head of each attribute tree is considered the "child"
1705 * of the file it is associated with and the ".." file refers
1706 * to the associated file. For any non-directory file with
1707 * attributes, the ".." entry in the unnamed directory refers
1708 * to a file that is not a directory.
1710 * Conceptually, the attribute model is fully general. Extended
1711 * attributes can be any type of file (doors, links, direc-
1712 * tories, and so forth) and can even have their own attributes
1713 * (fully recursive). As a result, the attributes associated
1714 * with a file could be an arbitrarily deep directory hierarchy
1715 * where each attribute could have an equally complex attribute
1716 * tree associated with it. Not all implementations are able
1717 * to, or want to, support the full model. Implementation are
1718 * therefore permitted to reject operations that are not sup-
1719 * ported. For example, the implementation for the UFS file
1720 * system allows only regular files as attributes (for example,
1721 * no sub-directories) and rejects attempts to place attributes
1724 * The following list details the operations that are rejected
1725 * in the current implementation:
1727 * link Any attempt to create links between
1728 * attribute and non-attribute space
1729 * is rejected to prevent security-
1730 * related or otherwise sensitive
1731 * attributes from being exposed, and
1732 * therefore manipulable, as regular
1735 * rename Any attempt to rename between
1736 * attribute and non-attribute space
1737 * is rejected to prevent an already
1738 * linked file from being renamed and
1739 * thereby circumventing the link res-
1742 * mkdir, symlink, mknod Any attempt to create a "non-
1743 * regular" file in attribute space is
1744 * rejected to reduce the functional-
1745 * ity, and therefore exposure and
1746 * risk, of the initial implementa-
1749 * The entire available name space has been allocated to "gen-
1750 * eral use" to bring the implementation in line with the NFSv4
1751 * draft standard [NFSv4]. That standard defines "named attri-
1752 * butes" (equivalent to Solaris Extended Attributes) with no
1753 * naming restrictions. All Sun applications making use of
1754 * opaque extended attributes will use the prefix "SUNW".
1757 #ifdef HAVE_SYS_ATTR_H
1758 #include <sys/attr.h>
1765 #ifdef HAVE_SYS_NVPAIR_H
1766 #include <sys/nvpair.h>
1769 #ifdef HAVE_SYS_ACL_H
1770 #include <sys/acl.h>
1773 #if !defined(HAVE_OPENAT) || \
1774 !defined(HAVE_UNLINKAT) || \
1775 !defined(HAVE_FCHOWNAT) || \
1776 !defined(HAVE_FUTIMESAT)
1777 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
1781 * Define the supported XATTR streams for this OS
1783 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1784 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
1786 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
1787 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
1790 * This code creates a temporary cache with entries for each xattr which has
1791 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
1793 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
1795 xattr_link_cache_entry_t *ptr;
1797 foreach_alist(ptr, jcr->xattr_data->link_cache) {
1798 if (ptr && ptr->inum == inum) {
1805 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
1807 xattr_link_cache_entry_t *ptr;
1809 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
1810 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
1812 bstrncpy(ptr->target, target, sizeof(ptr->target));
1813 jcr->xattr_data->link_cache->append(ptr);
1816 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1818 * This function returns true if a non default extended system attribute
1819 * list is associated with fd and returns false when an error has occured
1820 * or when only extended system attributes other than archive,
1821 * av_modified or crtime are set.
1823 * The function returns true for the following cases:
1825 * - any extended system attribute other than the default attributes
1826 * ('archive', 'av_modified' and 'crtime') is set
1827 * - nvlist has NULL name string
1828 * - nvpair has data type of 'nvlist'
1829 * - default data type.
1831 static bool solaris_has_non_transient_extensible_attributes(int fd)
1839 bool retval = false;
1841 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
1846 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
1847 name = nvpair_name(pair);
1850 fattr = name_to_attr(name);
1856 type = nvpair_type(pair);
1858 case DATA_TYPE_BOOLEAN_VALUE:
1859 if (nvpair_value_boolean_value(pair, &value) != 0) {
1862 if (value && fattr != F_ARCHIVE &&
1863 fattr != F_AV_MODIFIED) {
1868 case DATA_TYPE_UINT64_ARRAY:
1869 if (fattr != F_CRTIME) {
1874 case DATA_TYPE_NVLIST:
1882 if (response != NULL) {
1883 nvlist_free(response);
1887 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1889 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
1891 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1892 * There is no need to store those acls as we already store the stat bits too.
1894 static bool acl_is_trivial(int count, aclent_t *entries)
1899 for (n = 0; n < count; n++) {
1901 if (!(ace->a_type == USER_OBJ ||
1902 ace->a_type == GROUP_OBJ ||
1903 ace->a_type == OTHER_OBJ ||
1904 ace->a_type == CLASS_OBJ))
1909 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
1911 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
1914 #ifdef HAVE_EXTENDED_ACL
1920 * See if this attribute has an ACL
1922 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
1923 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
1925 * See if there is a non trivial acl on the file.
1927 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
1928 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
1931 return bxattr_exit_ok;
1933 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1934 attrname, jcr->last_fname, be.bstrerror());
1935 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
1936 attrname, jcr->last_fname, be.bstrerror());
1937 return bxattr_exit_error;
1942 #if defined(ACL_SID_FMT)
1944 * New format flag added in newer Solaris versions.
1946 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1948 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1949 #endif /* ACL_SID_FMT */
1951 *acl_text = acl_totext(aclp, flags);
1959 return bxattr_exit_ok;
1960 #else /* HAVE_EXTENDED_ACL */
1962 aclent_t *acls = NULL;
1966 * See if this attribute has an ACL
1969 n = facl(fd, GETACLCNT, 0, NULL);
1971 n = acl(attrname, GETACLCNT, 0, NULL);
1974 if (n >= MIN_ACL_ENTRIES) {
1975 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1976 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
1977 acl(attrname, GETACL, n, acls) != n) {
1981 return bxattr_exit_ok;
1983 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1984 attrname, jcr->last_fname, be.bstrerror());
1985 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
1986 attrname, jcr->last_fname, be.bstrerror());
1988 return bxattr_exit_error;
1993 * See if there is a non trivial acl on the file.
1995 if (!acl_is_trivial(n, acls)) {
1996 if ((*acl_text = acltotext(acls, n)) == NULL) {
1997 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
1998 attrname, jcr->last_fname, be.bstrerror());
1999 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2000 attrname, jcr->last_fname, be.bstrerror());
2002 return bxattr_exit_error;
2012 return bxattr_exit_ok;
2013 #endif /* HAVE_EXTENDED_ACL */
2015 #else /* HAVE_ACL */
2016 return bxattr_exit_ok;
2017 #endif /* HAVE_ACL */
2021 * Forward declaration for recursive function call.
2023 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2026 * Save an extended or extensible attribute.
2027 * This is stored as an opaque stream of bytes with the following encoding:
2029 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2031 * or for a hardlinked or symlinked attribute
2033 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2035 * xattr_name can be a subpath relative to the file the xattr is on.
2036 * stat_buffer is the string representation of the stat struct.
2037 * acl_string is an acl text when a non trivial acl is set on the xattr.
2038 * actual_xattr_data is the content of the xattr file.
2040 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2041 const char *attrname, bool toplevel_hidden_dir, int stream)
2046 xattr_link_cache_entry_t *xlce;
2047 char target_attrname[PATH_MAX];
2048 char link_source[PATH_MAX];
2049 char *acl_text = NULL;
2050 char attribs[MAXSTRING];
2051 char buffer[XATTR_BUFSIZ];
2052 bxattr_exit_code retval = bxattr_exit_error;
2055 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2058 * Get the stats of the extended or extensible attribute.
2060 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2063 retval = bxattr_exit_ok;
2066 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2067 target_attrname, jcr->last_fname, be.bstrerror());
2068 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2069 target_attrname, jcr->last_fname, be.bstrerror());
2075 * Based on the filetype perform the correct action. We support most filetypes here, more
2076 * then the actual implementation on Solaris supports so some code may never get executed
2077 * due to limitations in the implementation.
2079 switch (st.st_mode & S_IFMT) {
2084 * Get any acl on the xattr.
2086 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2090 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2091 * Encode the stat struct into an ASCII representation.
2093 encode_stat(attribs, &st, 0, stream);
2094 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2095 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2099 * Get any acl on the xattr.
2101 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2105 * See if this is the toplevel_hidden_dir being saved.
2107 if (toplevel_hidden_dir) {
2109 * Save the data for later storage when we encounter a real xattr. We store the data
2110 * in the jcr->xattr_data->content buffer and flush that just before sending out the
2111 * first real xattr. Encode the stat struct into an ASCII representation and jump
2112 * out of the function.
2114 encode_stat(attribs, &st, 0, stream);
2115 cnt = bsnprintf(buffer, sizeof(buffer),
2117 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2118 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2119 jcr->xattr_data->content_length = cnt;
2123 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2124 * Encode the stat struct into an ASCII representation.
2126 encode_stat(attribs, &st, 0, stream);
2127 cnt = bsnprintf(buffer, sizeof(buffer),
2129 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2134 * If this is a hardlinked file check the inode cache for a hit.
2136 if (st.st_nlink > 1) {
2138 * See if the cache already knows this inode number.
2140 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2142 * Generate a xattr encoding with the reference to the target in there.
2144 encode_stat(attribs, &st, st.st_ino, stream);
2145 cnt = bsnprintf(buffer, sizeof(buffer),
2147 target_attrname, 0, attribs, 0, xlce->target, 0);
2148 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2149 jcr->xattr_data->content_length = cnt;
2150 retval = send_xattr_stream(jcr, stream);
2153 * For a hard linked file we are ready now, no need to recursively save the attributes.
2159 * Store this hard linked file in the cache.
2160 * Store the name relative to the top level xattr space.
2162 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2166 * Get any acl on the xattr.
2168 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2173 * Encode the stat struct into an ASCII representation.
2175 encode_stat(attribs, &st, 0, stream);
2176 cnt = bsnprintf(buffer, sizeof(buffer),
2178 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2181 * Open the extended or extensible attribute file.
2183 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2186 retval = bxattr_exit_ok;
2189 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2190 target_attrname, jcr->last_fname, be.bstrerror());
2191 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2192 target_attrname, jcr->last_fname, be.bstrerror());
2199 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2200 * Encode the stat struct into an ASCII representation.
2202 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2205 retval = bxattr_exit_ok;
2208 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2209 target_attrname, jcr->last_fname, be.bstrerror());
2210 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2211 target_attrname, jcr->last_fname, be.bstrerror());
2217 * Generate a xattr encoding with the reference to the target in there.
2219 encode_stat(attribs, &st, st.st_ino, stream);
2220 cnt = bsnprintf(buffer, sizeof(buffer),
2222 target_attrname, 0, attribs, 0, link_source, 0);
2223 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2224 jcr->xattr_data->content_length = cnt;
2225 retval = send_xattr_stream(jcr, stream);
2227 if (retval == bxattr_exit_ok) {
2228 jcr->xattr_data->nr_saved++;
2232 * For a soft linked file we are ready now, no need to recursively save the attributes.
2240 * See if this is the first real xattr being saved.
2241 * If it is save the toplevel_hidden_dir attributes first.
2242 * This is easy as its stored already in the jcr->xattr_data->content buffer.
2244 if (jcr->xattr_data->nr_saved == 0) {
2245 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2246 if (retval != bxattr_exit_ok) {
2249 jcr->xattr_data->nr_saved++;
2252 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2253 jcr->xattr_data->content_length = cnt;
2256 * Only dump the content of regular files.
2258 switch (st.st_mode & S_IFMT) {
2260 if (st.st_size > 0) {
2262 * Protect ourself against things getting out of hand.
2264 if (st.st_size >= MAX_XATTR_STREAM) {
2265 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2266 jcr->last_fname, MAX_XATTR_STREAM);
2270 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2271 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
2272 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
2273 jcr->xattr_data->content_length += cnt;
2277 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
2278 target_attrname, jcr->last_fname);
2279 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2280 target_attrname, jcr->last_fname);
2291 retval = send_xattr_stream(jcr, stream);
2292 if (retval == bxattr_exit_ok) {
2293 jcr->xattr_data->nr_saved++;
2298 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2299 * available on this extended attribute.
2302 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2305 * The recursive call could change our working dir so change back to the wanted workdir.
2307 if (fchdir(fd) < 0) {
2310 retval = bxattr_exit_ok;
2313 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2314 jcr->last_fname, be.bstrerror());
2315 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2316 jcr->last_fname, fd, be.bstrerror());
2323 if (acl_text != NULL) {
2332 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2335 int fd, filefd = -1, attrdirfd = -1;
2338 char current_xattr_namespace[PATH_MAX];
2339 bxattr_exit_code retval = bxattr_exit_error;
2343 * Determine what argument to use. Use attr_parent when set
2344 * (recursive call) or jcr->last_fname for first call. Also save
2345 * the current depth of the xattr_space we are in.
2349 if (xattr_namespace) {
2350 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2351 xattr_namespace, attr_parent);
2353 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2356 name = jcr->last_fname;
2357 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2361 * Open the file on which to save the xattrs read-only.
2363 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2366 retval = bxattr_exit_ok;
2369 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2370 jcr->last_fname, be.bstrerror());
2371 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2372 jcr->last_fname, be.bstrerror());
2378 * Open the xattr naming space.
2380 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2384 * Gentile way of the system saying this type of xattr layering is not supported.
2385 * Which is not problem we just forget about this this xattr.
2386 * But as this is not an error we return a positive return value.
2388 retval = bxattr_exit_ok;
2391 retval = bxattr_exit_ok;
2394 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2395 name, jcr->last_fname, be.bstrerror());
2396 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2397 name, jcr->last_fname, be.bstrerror());
2403 * We need to change into the attribute directory to determine if each of the
2404 * attributes should be saved.
2406 if (fchdir(attrdirfd) < 0) {
2407 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2408 jcr->last_fname, be.bstrerror());
2409 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2410 jcr->last_fname, attrdirfd, be.bstrerror());
2415 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2416 * else because the readdir returns "." entry after the extensible attr entry.
2417 * And as we want this entry before anything else we better just save its data.
2420 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2421 true, STREAM_XATTR_SOLARIS);
2423 if ((fd = dup(attrdirfd)) == -1 ||
2424 (dirp = fdopendir(fd)) == (DIR *)NULL) {
2425 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2426 jcr->last_fname, be.bstrerror());
2427 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
2428 jcr->last_fname, fd, be.bstrerror());
2434 * Walk the namespace.
2436 while ((dp = readdir(dirp)) != NULL) {
2438 * Skip only the toplevel . dir.
2440 if (!attr_parent && bstrcmp(dp->d_name, "."))
2444 * Skip all .. directories
2446 if (bstrcmp(dp->d_name, ".."))
2449 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2450 current_xattr_namespace, dp->d_name, jcr->last_fname);
2452 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2454 * We are not interested in read-only extensible attributes.
2456 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2457 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2458 current_xattr_namespace, dp->d_name, jcr->last_fname);
2464 * We are only interested in read-write extensible attributes
2465 * when they contain non-transient values.
2467 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2469 * Determine if there are non-transient system attributes at the toplevel.
2470 * We need to provide a fd to the open file.
2472 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2473 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2474 current_xattr_namespace, dp->d_name, jcr->last_fname);
2481 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2482 false, STREAM_XATTR_SOLARIS_SYS);
2485 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2490 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2491 false, STREAM_XATTR_SOLARIS);
2495 retval = bxattr_exit_ok;
2498 if (attrdirfd != -1)
2506 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
2508 #ifdef HAVE_EXTENDED_ACL
2513 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
2514 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
2516 return bxattr_exit_error;
2519 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
2520 acl_set(attrname, aclp) != 0) {
2521 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2522 attrname, jcr->last_fname, be.bstrerror());
2523 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2524 attrname, jcr->last_fname, be.bstrerror());
2525 return bxattr_exit_error;
2531 return bxattr_exit_ok;
2533 #else /* HAVE_EXTENDED_ACL */
2535 aclent_t *acls = NULL;
2538 acls = aclfromtext(acl_text, &n);
2540 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
2541 acl(attrname, SETACL, n, acls) != 0) {
2542 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2543 attrname, jcr->last_fname, be.bstrerror());
2544 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2545 attrname, jcr->last_fname, be.bstrerror());
2546 return bxattr_exit_error;
2553 return bxattr_exit_ok;
2555 #endif /* HAVE_EXTENDED_ACL */
2558 #endif /* HAVE_ACL */
2560 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
2562 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
2563 int used_bytes, total_bytes, cnt;
2564 char *bp, *target_attrname, *attribs;
2565 char *linked_target = NULL;
2566 char *acl_text = NULL;
2570 struct timeval times[2];
2571 bxattr_exit_code retval = bxattr_exit_error;
2575 * Parse the xattr stream. First the part that is the same for all xattrs.
2578 total_bytes = jcr->xattr_data->content_length;
2581 * The name of the target xattr has a leading / we are not interested
2582 * in that so skip it when decoding the string. We always start a the /
2583 * of the xattr space anyway.
2585 target_attrname = jcr->xattr_data->content + 1;
2586 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
2587 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2593 * Open the file on which to restore the xattrs read-only.
2595 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
2596 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2597 jcr->last_fname, be.bstrerror());
2598 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2599 jcr->last_fname, be.bstrerror());
2604 * Open the xattr naming space and make it the current working dir.
2606 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2607 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
2608 jcr->last_fname, be.bstrerror());
2609 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
2610 jcr->last_fname, be.bstrerror());
2614 if (fchdir(attrdirfd) < 0) {
2615 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2616 jcr->last_fname, be.bstrerror());
2617 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2618 jcr->last_fname, attrdirfd, be.bstrerror());
2623 * Try to open the correct xattr subdir based on the target_attrname given.
2624 * e.g. check if its a subdir attrname. Each / in the string makes us go
2627 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2630 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2631 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2632 target_attrname, jcr->last_fname, be.bstrerror());
2633 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2634 target_attrname, jcr->last_fname, be.bstrerror());
2642 * Open the xattr naming space.
2644 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2645 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2646 target_attrname, jcr->last_fname, be.bstrerror());
2647 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2648 target_attrname, jcr->last_fname, be.bstrerror());
2656 * Make the xattr space our current workingdir.
2658 if (fchdir(attrdirfd) < 0) {
2659 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2660 target_attrname, jcr->last_fname, be.bstrerror());
2661 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2662 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2666 target_attrname = ++bp;
2670 * Decode the attributes from the stream.
2672 decode_stat(attribs, &st, &inum);
2675 * Decode the next field (acl_text).
2677 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2678 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2684 * Based on the filetype perform the correct action. We support most filetypes here, more
2685 * then the actual implementation on Solaris supports so some code may never get executed
2686 * due to limitations in the implementation.
2688 switch (st.st_mode & S_IFMT) {
2691 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2693 unlinkat(attrdirfd, target_attrname, 0);
2694 if (mkfifo(target_attrname, st.st_mode) < 0) {
2695 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
2696 target_attrname, jcr->last_fname, be.bstrerror());
2697 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
2698 target_attrname, jcr->last_fname, be.bstrerror());
2705 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2707 unlinkat(attrdirfd, target_attrname, 0);
2708 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
2709 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
2710 target_attrname, jcr->last_fname, be.bstrerror());
2711 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
2712 target_attrname, jcr->last_fname, be.bstrerror());
2718 * If its not the hidden_dir create the entry.
2719 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2721 if (!bstrcmp(target_attrname, ".")) {
2722 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
2723 if (mkdir(target_attrname, st.st_mode) < 0) {
2724 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
2725 target_attrname, jcr->last_fname, be.bstrerror());
2726 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
2727 target_attrname, jcr->last_fname, be.bstrerror());
2734 * See if this is a hard linked file. e.g. inum != 0
2739 unlinkat(attrdirfd, target_attrname, 0);
2740 if (link(linked_target, target_attrname) < 0) {
2741 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
2742 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2743 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
2744 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2749 * Successfully restored xattr.
2751 retval = bxattr_exit_ok;
2754 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
2755 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
2759 if (used_bytes < (total_bytes - 1))
2763 * Restore the actual xattr.
2765 if (!is_extensible) {
2766 unlinkat(attrdirfd, target_attrname, 0);
2769 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
2770 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2771 target_attrname, jcr->last_fname, be.bstrerror());
2772 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2773 target_attrname, jcr->last_fname, be.bstrerror());
2779 * Restore the actual data.
2781 if (st.st_size > 0) {
2782 used_bytes = (data - jcr->xattr_data->content);
2783 cnt = total_bytes - used_bytes;
2786 * Do a sanity check, the st.st_size should be the same as the number of bytes
2787 * we have available as data of the stream.
2789 if (cnt != st.st_size) {
2790 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
2791 target_attrname, jcr->last_fname);
2792 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
2793 target_attrname, jcr->last_fname);
2798 cnt = write(attrfd, data, cnt);
2800 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
2801 target_attrname, jcr->last_fname, be.bstrerror());
2802 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
2803 target_attrname, jcr->last_fname, be.bstrerror());
2809 cnt = total_bytes - used_bytes;
2815 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2819 if (symlink(linked_target, target_attrname) < 0) {
2820 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
2821 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2822 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
2823 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2828 * Successfully restored xattr.
2830 retval = bxattr_exit_ok;
2837 * Restore owner and acl for non extensible attributes.
2839 if (!is_extensible) {
2840 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
2844 * Gentile way of the system saying this type of xattr layering is not supported.
2845 * But as this is not an error we return a positive return value.
2847 retval = bxattr_exit_ok;
2850 retval = bxattr_exit_ok;
2853 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
2854 target_attrname, jcr->last_fname, be.bstrerror());
2855 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
2856 target_attrname, jcr->last_fname, be.bstrerror());
2863 if (acl_text && *acl_text)
2864 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
2866 #endif /* HAVE_ACL */
2869 * For a non extensible attribute restore access and modification time on the xattr.
2871 if (!is_extensible) {
2872 times[0].tv_sec = st.st_atime;
2873 times[0].tv_usec = 0;
2874 times[1].tv_sec = st.st_mtime;
2875 times[1].tv_usec = 0;
2877 if (futimesat(attrdirfd, target_attrname, times) < 0) {
2878 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
2879 target_attrname, jcr->last_fname, be.bstrerror());
2880 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
2881 target_attrname, jcr->last_fname, be.bstrerror());
2887 * Successfully restored xattr.
2889 retval = bxattr_exit_ok;
2893 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
2895 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
2902 if (attrdirfd != -1) {
2911 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2914 bxattr_exit_code retval = bxattr_exit_ok;
2917 * First see if extended attributes or extensible attributes are present.
2918 * If not just pretend things went ok.
2920 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
2921 jcr->xattr_data->nr_saved = 0;
2922 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
2925 * As we change the cwd in the save function save the current cwd
2926 * for restore after return from the solaris_save_xattrs function.
2928 getcwd(cwd, sizeof(cwd));
2929 retval = solaris_save_xattrs(jcr, NULL, NULL);
2931 delete jcr->xattr_data->link_cache;
2932 jcr->xattr_data->link_cache = NULL;
2937 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
2940 bool is_extensible = false;
2941 bxattr_exit_code retval;
2944 * First make sure we can restore xattr on the filesystem.
2947 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2948 case STREAM_XATTR_SOLARIS_SYS:
2949 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
2950 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
2951 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
2953 return bxattr_exit_error;
2956 is_extensible = true;
2959 case STREAM_XATTR_SOLARIS:
2960 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
2961 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
2962 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
2964 return bxattr_exit_error;
2968 return bxattr_exit_error;
2972 * As we change the cwd in the restore function save the current cwd
2973 * for restore after return from the solaris_restore_xattrs function.
2975 getcwd(cwd, sizeof(cwd));
2976 retval = solaris_restore_xattrs(jcr, is_extensible);
2983 * Function pointers to the build and parse function to use for these xattrs.
2985 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
2986 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
2988 #endif /* defined(HAVE_SUN_OS) */
2991 * Entry points when compiled with support for XATTRs on a supported platform.
2993 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2995 if (os_build_xattr_streams) {
2996 return (*os_build_xattr_streams)(jcr, ff_pkt);
2998 return bxattr_exit_error;
3001 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
3005 if (os_parse_xattr_streams) {
3007 * See if we can parse this stream, and ifso give it a try.
3009 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3010 if (os_default_xattr_streams[cnt] == stream) {
3011 return (*os_parse_xattr_streams)(jcr, stream);
3016 * Issue a warning and discard the message. But pretend the restore was ok.
3018 Jmsg2(jcr, M_WARNING, 0,
3019 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3020 jcr->last_fname, stream);
3021 return bxattr_exit_error;