2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2012 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 * - FreeBSD (Extended Attributes)
38 * - GNU HURD (Extended Attributes)
39 * - IRIX (Extended Attributes)
40 * - Linux (Extended Attributes)
41 * - NetBSD (Extended Attributes)
42 * - OpenBSD (Extended Attributes)
43 * (As it seems either they never implemented xattr or they are removed
44 * the support as it stated it was in version 3.1 but the current syscall
45 * tabled shows the extattr_ functions are not implemented. So as such we
46 * might eventually support xattr on OpenBSD when they implemented them using
47 * the same interface as FreeBSD and NetBSD.
48 * - Solaris (Extended Attributes and Extensible Attributes)
49 * - Tru64 (Extended Attributes)
51 * Written by Marco van Wieringen, November 2008
52 * Major overhaul January 2012 + June 2012
58 #if !defined(HAVE_XATTR)
60 * Entry points when compiled without support for XATTRs or on an unsupported platform.
62 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
64 return bxattr_exit_fatal;
67 bxattr_exit_code parse_xattr_streams(JCR *jcr,
70 uint32_t content_length)
72 return bxattr_exit_fatal;
76 * Send a XATTR stream to the SD.
78 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
80 BSOCK *sd = jcr->store_bsock;
82 #ifdef FD_NO_SEND_TEST
83 return bxattr_exit_ok;
89 if (jcr->xattr_data->u.build->content_length <= 0) {
90 return bxattr_exit_ok;
96 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
97 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
99 return bxattr_exit_fatal;
103 * Send the buffer to the storage deamon
105 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->u.build->content);
107 sd->msg = jcr->xattr_data->u.build->content;
108 sd->msglen = jcr->xattr_data->u.build->content_length;
112 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
114 return bxattr_exit_fatal;
117 jcr->JobBytes += sd->msglen;
119 if (!sd->signal(BNET_EOD)) {
120 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
122 return bxattr_exit_fatal;
124 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
125 return bxattr_exit_ok;
129 * First some generic functions for OSes that use the same xattr encoding scheme.
130 * Currently for all OSes except for Solaris.
132 #if !defined(HAVE_SUN_OS)
133 static void xattr_drop_internal_table(alist *xattr_value_list)
135 xattr_t *current_xattr;
138 * Walk the list of xattrs and free allocated memory on traversing.
140 foreach_alist(current_xattr, xattr_value_list) {
142 * See if we can shortcut.
144 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
147 free(current_xattr->name);
149 if (current_xattr->value_length > 0)
150 free(current_xattr->value);
155 delete xattr_value_list;
159 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
160 * which encodes one or more xattr_t structures.
162 * The Serialized stream consists of the following elements:
163 * magic - A magic string which makes it easy to detect any binary incompatabilites
164 * name_length - The length of the following xattr name
165 * name - The name of the extended attribute
166 * value_length - The length of the following xattr data
167 * value - The actual content of the extended attribute
169 * This is repeated 1 or more times.
172 static uint32_t serialize_xattr_stream(JCR *jcr,
173 uint32_t expected_serialize_len,
174 alist *xattr_value_list)
176 xattr_t *current_xattr;
180 * Make sure the serialized stream fits in the poolmem buffer.
181 * We allocate some more to be sure the stream is gonna fit.
183 jcr->xattr_data->u.build->content =
184 check_pool_memory_size(jcr->xattr_data->u.build->content,
185 expected_serialize_len + 10);
186 ser_begin(jcr->xattr_data->u.build->content,
187 expected_serialize_len + 10);
190 * Walk the list of xattrs and serialize the data.
192 foreach_alist(current_xattr, xattr_value_list) {
194 * See if we can shortcut.
196 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
199 ser_uint32(current_xattr->magic);
200 ser_uint32(current_xattr->name_length);
201 ser_bytes(current_xattr->name, current_xattr->name_length);
203 ser_uint32(current_xattr->value_length);
204 if (current_xattr->value_length > 0 && current_xattr->value) {
205 ser_bytes(current_xattr->value, current_xattr->value_length);
207 Dmsg3(100, "Backup xattr named %s, value %*s\n",
208 current_xattr->name, current_xattr->value, current_xattr->value);
210 Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
214 ser_end(jcr->xattr_data->u.build->content, expected_serialize_len + 10);
215 jcr->xattr_data->u.build->content_length =
216 ser_length(jcr->xattr_data->u.build->content);
218 return jcr->xattr_data->u.build->content_length;
221 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr,
223 uint32_t content_length,
224 alist *xattr_value_list)
227 xattr_t *current_xattr;
230 * Parse the stream and call restore_xattr_on_file for each extended attribute.
232 * Start unserializing the data. We keep on looping while we have not
233 * unserialized all bytes in the stream.
235 unser_begin(content, content_length);
236 while (unser_length(content) < content_length) {
238 * First make sure the magic is present. This way we can easily catch corruption.
239 * Any missing MAGIC is fatal we do NOT try to continue.
241 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
242 unser_uint32(current_xattr->magic);
243 if (current_xattr->magic != XATTR_MAGIC) {
245 _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
247 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
250 return bxattr_exit_error;
254 * Decode the valuepair. First decode the length of the name.
256 unser_uint32(current_xattr->name_length);
257 if (current_xattr->name_length == 0) {
259 _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
261 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
264 return bxattr_exit_error;
268 * Allocate room for the name and decode its content.
270 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
271 unser_bytes(current_xattr->name, current_xattr->name_length);
274 * The xattr_name needs to be null terminated.
276 current_xattr->name[current_xattr->name_length] = '\0';
279 * Decode the value length.
281 unser_uint32(current_xattr->value_length);
283 if (current_xattr->value_length > 0) {
285 * Allocate room for the value and decode its content.
287 current_xattr->value = (char *)malloc(current_xattr->value_length);
288 unser_bytes(current_xattr->value, current_xattr->value_length);
290 Dmsg3(100, "Restoring xattr named %s, value %*s\n",
291 current_xattr->name, current_xattr->value, current_xattr->value);
293 current_xattr->value = NULL;
294 Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
297 xattr_value_list->append(current_xattr);
300 unser_end(content, content_length);
301 return bxattr_exit_ok;
306 * This is a supported OS, See what kind of interface we should use.
308 #if defined(HAVE_AIX_OS)
310 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
311 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
312 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
313 #error "Missing full support for the Extended Attributes (EA) functions."
319 #error "Missing sys/ea.h header file"
323 * Define the supported XATTR streams for this OS
325 static int os_default_xattr_streams[1] = {
330 * Fallback to the non l-functions when those are not available.
332 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
335 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
338 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
339 #define llistea listea
342 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
346 char *xattr_list = NULL;
347 int cnt, xattr_count = 0;
348 uint32_t name_length;
349 int32_t xattr_list_len,
351 uint32_t expected_serialize_len = 0;
352 xattr_t *current_xattr;
353 alist *xattr_value_list = NULL;
354 bxattr_exit_code retval = bxattr_exit_error;
357 * First get the length of the available list with extended attributes.
359 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
360 switch (xattr_list_len) {
367 retval = bxattr_exit_ok;
371 * If the filesystem reports it doesn't support XATTRs we clear the
372 * BXATTR_FLAG_SAVE_NATIVE flag so we skip XATTR saves on all other files
373 * on the same filesystem. The BXATTR_FLAG_SAVE_NATIVE flags gets sets again
374 * when we change from one filesystem to an other.
376 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
377 retval = bxattr_exit_ok;
381 _("llistea error on file \"%s\": ERR=%s\n"),
382 jcr->last_fname, be.bstrerror());
383 Dmsg2(100, "llistea error file=%s ERR=%s\n",
384 jcr->last_fname, be.bstrerror());
390 retval = bxattr_exit_ok;
397 * Allocate room for the extented attribute list.
399 xattr_list = (char *)malloc(xattr_list_len + 1);
400 memset(xattr_list, 0, xattr_list_len + 1);
403 * Get the actual list of extended attributes names for a file.
405 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
406 switch (xattr_list_len) {
413 retval = bxattr_exit_ok;
417 _("llistea error on file \"%s\": ERR=%s\n"),
418 jcr->last_fname, be.bstrerror());
419 Dmsg2(100, "llistea error file=%s ERR=%s\n",
420 jcr->last_fname, be.bstrerror());
428 xattr_list[xattr_list_len] = '\0';
431 * Walk the list of extended attributes names and retrieve the data.
432 * We already count the bytes needed for serializing the stream later on.
434 for (bp = xattr_list;
435 (bp - xattr_list) + 1 < xattr_list_len;
436 bp = strchr(bp, '\0') + 1) {
440 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
446 name_length = strlen(bp);
447 if (skip_xattr || name_length == 0) {
448 Dmsg1(100, "Skipping xattr named %s\n", bp);
453 * First see how long the value is for the extended attribute.
455 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
456 switch (xattr_value_len) {
463 retval = bxattr_exit_ok;
467 _("lgetea error on file \"%s\": ERR=%s\n"),
468 jcr->last_fname, be.bstrerror());
469 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
470 jcr->last_fname, be.bstrerror());
480 * Each xattr valuepair starts with a magic so we can parse it easier.
482 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
483 current_xattr->magic = XATTR_MAGIC;
484 expected_serialize_len += sizeof(current_xattr->magic);
487 * Allocate space for storing the name.
489 current_xattr->name_length = name_length;
490 current_xattr->name = (char *)malloc(current_xattr->name_length);
491 memcpy(current_xattr->name, bp, current_xattr->name_length);
493 expected_serialize_len += sizeof(current_xattr->name_length) +
494 current_xattr->name_length;
496 switch (xattr_value_len) {
498 current_xattr->value = NULL;
499 current_xattr->value_length = 0;
500 expected_serialize_len += sizeof(current_xattr->value_length);
504 * Allocate space for storing the value.
506 current_xattr->value = (char *)malloc(xattr_value_len);
507 memset(current_xattr->value, 0, xattr_value_len);
509 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
510 if (xattr_value_len < 0) {
516 retval = bxattr_exit_ok;
520 _("lgetea error on file \"%s\": ERR=%s\n"),
521 jcr->last_fname, be.bstrerror());
522 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
523 jcr->last_fname, be.bstrerror());
528 * Default failure path out when retrieval of attr fails.
530 free(current_xattr->value);
531 free(current_xattr->name);
536 * Store the actual length of the value.
538 current_xattr->value_length = xattr_value_len;
539 expected_serialize_len += sizeof(current_xattr->value_length) +
540 current_xattr->value_length;
544 if (xattr_value_list == NULL) {
545 xattr_value_list = New(alist(10, not_owned_by_alist));
548 xattr_value_list->append(current_xattr);
552 * Protect ourself against things getting out of hand.
554 if (expected_serialize_len >= MAX_XATTR_STREAM) {
556 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
557 jcr->last_fname, MAX_XATTR_STREAM);
563 xattr_list = (char *)NULL;
566 * If we found any xattr send them to the SD.
568 if (xattr_count > 0) {
570 * Serialize the datastream.
572 if (serialize_xattr_stream(jcr,
573 expected_serialize_len,
574 xattr_value_list) < expected_serialize_len) {
576 _("Failed to serialize extended attributes on file \"%s\"\n"),
578 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
584 * Send the datastream to the SD.
586 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
588 retval = bxattr_exit_ok;
592 if (xattr_list != NULL) {
595 if (xattr_value_list != NULL) {
596 xattr_drop_internal_table(xattr_value_list);
602 static bxattr_exit_code aix_parse_xattr_streams(JCR *jcr,
605 uint32_t content_length)
607 xattr_t *current_xattr;
608 alist *xattr_value_list;
609 bxattr_exit_code retval = bxattr_exit_error;
611 xattr_value_list = New(alist(10, not_owned_by_alist));
613 if (unserialize_xattr_stream(jcr,
616 xattr_value_list) != bxattr_exit_ok) {
620 foreach_alist(current_xattr, xattr_value_list) {
621 if (lsetea(jcr->last_fname,
623 current_xattr->value,
624 current_xattr->value_length, 0) != 0) {
633 * If the filesystem reports it doesn't support XATTRs we clear
634 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
635 * on all other files on the same filesystem. The
636 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
637 * change from one filesystem to an other.
639 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
643 _("lsetea error on file \"%s\": ERR=%s\n"),
644 jcr->last_fname, be.bstrerror());
645 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
646 jcr->last_fname, be.bstrerror());
652 retval = bxattr_exit_ok;
655 xattr_drop_internal_table(xattr_value_list);
661 * Function pointers to the build and parse function to use for these xattrs.
663 static bxattr_exit_code (*os_build_xattr_streams)
664 (JCR *jcr, FF_PKT *ff_pkt) =
665 aix_xattr_build_streams;
666 static bxattr_exit_code (*os_parse_xattr_streams)
667 (JCR *jcr, int stream, char *content, uint32_t content_length) =
668 aix_parse_xattr_streams;
670 #elif defined(HAVE_IRIX_OS)
672 #include <sys/attributes.h>
675 * Define the supported XATTR streams for this OS
677 static int os_default_xattr_streams[1] = {
680 static const char *xattr_acl_skiplist[1] = {
683 static const char *xattr_skiplist[1] = {
687 struct xattr_naming_space {
692 static xattr_naming_space xattr_naming_spaces[] = {
698 ATTR_ROOT | ATTR_DONTFOLLOW
705 static bxattr_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
708 int cnt, length, xattr_count = 0;
709 attrlist_cursor_t cursor;
710 attrlist_t *attrlist;
711 attrlist_ent_t *attrlist_ent;
712 xattr_t *current_xattr;
713 alist *xattr_value_list = NULL;
714 uint32_t expected_serialize_len = 0;
715 bxattr_exit_code retval = bxattr_exit_error;
716 POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
718 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
719 memset(&cursor, 0, sizeof(attrlist_cursor_t));
721 if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
722 xattr_naming_spaces[cnt].flags, &cursor) != 0) {
727 retval = bxattr_exit_ok;
731 _("attr_list error on file \"%s\": ERR=%s\n"),
732 jcr->last_fname, be.bstrerror());
733 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
734 jcr->last_fname, be.bstrerror());
739 attrlist = (attrlist_t *)xattrbuf;
742 * Walk the available attributes.
744 for (cnt = 0; cnt < attrlist->al_count; cnt++) {
745 attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
748 * First determine if we can retrieve the xattr and how big it really is.
750 length = sizeof(dummy);
751 if (attr_get(jcr->last_fname, attrlist_ent->a_name, dummy,
752 &length, xattr_naming_spaces[cnt].flags) != 0) {
758 retval = bxattr_exit_ok;
762 * Size of the xattr is bigger then the 32 bytes dummy which is
763 * likely. As length now contains its actual length we can allocate
764 * a properly size buffer for the real retrieval.
769 _("attr_list error on file \"%s\": ERR=%s\n"),
770 jcr->last_fname, be.bstrerror());
771 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
772 jcr->last_fname, be.bstrerror());
778 * Each xattr valuepair starts with a magic so we can parse it easier.
780 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
781 current_xattr->magic = XATTR_MAGIC;
782 expected_serialize_len += sizeof(current_xattr->magic);
785 * Allocate space for storing the name.
786 * We store the name as <naming_space_name><xattr_name>
788 current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) +
789 strlen(attrlist_ent->a_name) + 1;
790 current_xattr->name = (char *)malloc(current_xattr->name_length);
791 bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
792 xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
794 expected_serialize_len += sizeof(current_xattr->name_length) +
795 current_xattr->name_length;
797 current_xattr->value_length = length;
798 current_xattr->value = (char *)malloc(current_xattr->value_length);
801 * Retrieve the actual value of the xattr.
803 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
804 &length, xattr_naming_spaces[cnt].flags) != 0) {
810 retval = bxattr_exit_ok;
814 * The buffer for the xattr isn't big enough. the value of
815 * current_xattr->value_length is updated with the actual size
816 * of the xattr. So we free the old buffer and create a new one
817 * and try again. Normally this cannot happen as we size the
818 * buffer using a call to attr_get before but in case of an
819 * race condition it might happen.
821 free(current_xattr->value);
822 current_xattr->value = (char *)malloc(length);
823 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
824 &length, xattr_naming_spaces[cnt].flags) != 0) {
828 retval = bxattr_exit_ok;
832 _("attr_list error on file \"%s\": ERR=%s\n"),
833 jcr->last_fname, be.bstrerror(errno));
834 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
835 jcr->last_fname, be.bstrerror());
844 _("attr_list error on file \"%s\": ERR=%s\n"),
845 jcr->last_fname, be.bstrerror());
846 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
847 jcr->last_fname, be.bstrerror());
852 * Default failure path out when retrieval of attr fails.
854 free(current_xattr->value);
855 free(current_xattr->name);
861 current_xattr->value_length = length;
862 expected_serialize_len += sizeof(current_xattr->value_length) +
863 current_xattr->value_length;
865 if (xattr_value_list == NULL) {
866 xattr_value_list = New(alist(10, not_owned_by_alist));
869 xattr_value_list->append(current_xattr);
873 * Protect ourself against things getting out of hand.
875 if (expected_serialize_len >= MAX_XATTR_STREAM) {
877 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
878 jcr->last_fname, MAX_XATTR_STREAM);
884 * See if there are more attributes available for a next run of attr_list.
886 if (attrlist->al_more == 0) {
893 * If we found any xattr send them to the SD.
895 if (xattr_count > 0) {
897 * Serialize the datastream.
899 if (serialize_xattr_stream(jcr,
900 expected_serialize_len,
901 xattr_value_list) < expected_serialize_len) {
903 _("Failed to serialize extended attributes on file \"%s\"\n"),
905 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
911 * Send the datastream to the SD.
913 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
915 retval = bxattr_exit_ok;
919 free_pool_memory(xattrbuf);
921 if (xattr_value_list != NULL) {
922 xattr_drop_internal_table(xattr_value_list);
928 static bxattr_exit_code irix_parse_xattr_streams(JCR *jcr,
931 uint32_t content_length)
934 int cnt, cmp_size, name_space_index, flags;
935 xattr_t *current_xattr;
936 alist *xattr_value_list;
937 bxattr_exit_code retval = bxattr_exit_error;
939 xattr_value_list = New(alist(10, not_owned_by_alist));
941 if (unserialize_xattr_stream(jcr,
944 xattr_value_list) != bxattr_exit_ok) {
948 foreach_alist(current_xattr, xattr_value_list) {
950 * See to what namingspace this xattr belongs to.
952 name_space_index = 0;
953 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
954 cmp_size = strlen(xattr_naming_spaces[cnt].name);
955 if (!strncasecmp(current_xattr->name,
956 xattr_naming_spaces[cnt].name,
958 name_space_index = cnt;
964 * If we got a xattr that doesn't belong to an valid namespace complain.
966 if (name_space_index == 0) {
968 _("Received illegal xattr named %s on file \"%s\"\n"),
969 current_xattr->name, jcr->last_fname);
970 Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
971 current_xattr->name, jcr->last_fname);
976 * Restore the xattr first try to create the attribute from scratch.
978 flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
979 bp = strchr(current_xattr->name, '.');
980 if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
981 current_xattr->value_length, flags) != 0) {
986 retval = bxattr_exit_ok;
990 * The xattr already exists we need to replace it.
992 flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
993 if (attr_set(jcr->last_fname, bp, current_xattr->value,
994 current_xattr->value_length, flags) != 0) {
997 retval = bxattr_exit_ok;
1001 _("attr_set error on file \"%s\": ERR=%s\n"),
1002 jcr->last_fname, be.bstrerror(errno));
1003 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
1004 jcr->last_fname, be.bstrerror());
1011 _("attr_set error on file \"%s\": ERR=%s\n"),
1012 jcr->last_fname, be.bstrerror());
1013 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
1014 jcr->last_fname, be.bstrerror());
1020 retval = bxattr_exit_ok;
1023 xattr_drop_internal_table(xattr_value_list);
1029 * Function pointers to the build and parse function to use for these xattrs.
1031 static bxattr_exit_code (*os_build_xattr_streams)
1032 (JCR *jcr, FF_PKT *ff_pkt) =
1033 irix_xattr_build_streams;
1034 static bxattr_exit_code (*os_parse_xattr_streams)
1035 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1036 irix_parse_xattr_streams;
1038 #elif defined(HAVE_DARWIN_OS) || \
1039 defined(HAVE_LINUX_OS) || \
1040 defined(HAVE_HURD_OS)
1042 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
1043 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
1044 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
1045 #error "Missing full support for the XATTR functions."
1048 #ifdef HAVE_SYS_XATTR_H
1049 #include <sys/xattr.h>
1051 #error "Missing sys/xattr.h header file"
1055 * Define the supported XATTR streams for this OS
1057 #if defined(HAVE_DARWIN_OS)
1058 static int os_default_xattr_streams[1] = {
1061 static const char *xattr_acl_skiplist[2] = {
1062 "com.apple.system.Security",
1065 static const char *xattr_skiplist[3] = {
1066 "com.apple.system.extendedsecurity",
1067 "com.apple.ResourceFork",
1070 #elif defined(HAVE_LINUX_OS)
1071 static int os_default_xattr_streams[1] = {
1074 static const char *xattr_acl_skiplist[3] = {
1075 "system.posix_acl_access",
1076 "system.posix_acl_default",
1079 static const char *xattr_skiplist[1] = {
1082 #elif defined(HAVE_HURD_OS)
1083 static int os_default_xattr_streams[1] = {
1086 static const char *xattr_acl_skiplist[1] = {
1089 static const char *xattr_skiplist[1] = {
1095 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
1096 * listxattr, getxattr and setxattr with an extra options argument
1097 * which mimics the l variants of the functions when we specify
1098 * XATTR_NOFOLLOW as the options value.
1100 #if defined(HAVE_DARWIN_OS)
1101 #define llistxattr(path, list, size) \
1102 listxattr((path), (list), (size), XATTR_NOFOLLOW)
1103 #define lgetxattr(path, name, value, size) \
1104 getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
1105 #define lsetxattr(path, name, value, size, flags) \
1106 setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
1109 * Fallback to the non l-functions when those are not available.
1111 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
1112 #define lgetxattr getxattr
1114 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
1115 #define lsetxattr setxattr
1117 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
1118 #define llistxattr listxattr
1122 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
1126 char *xattr_list = NULL;
1127 int cnt, xattr_count = 0;
1128 uint32_t name_length;
1129 int32_t xattr_list_len,
1131 uint32_t expected_serialize_len = 0;
1132 xattr_t *current_xattr;
1133 alist *xattr_value_list = NULL;
1134 bxattr_exit_code retval = bxattr_exit_error;
1137 * First get the length of the available list with extended attributes.
1139 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
1140 switch (xattr_list_len) {
1146 retval = bxattr_exit_ok;
1148 case BXATTR_ENOTSUP:
1150 * If the filesystem reports it doesn't support XATTRs we clear
1151 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1152 * on all other files on the same filesystem. The
1153 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1154 * change from one filesystem to an other.
1156 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1157 retval = bxattr_exit_ok;
1161 _("llistxattr error on file \"%s\": ERR=%s\n"),
1162 jcr->last_fname, be.bstrerror());
1163 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1164 jcr->last_fname, be.bstrerror());
1170 retval = bxattr_exit_ok;
1177 * Allocate room for the extented attribute list.
1179 xattr_list = (char *)malloc(xattr_list_len + 1);
1180 memset(xattr_list, 0, xattr_list_len + 1);
1183 * Get the actual list of extended attributes names for a file.
1185 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
1186 switch (xattr_list_len) {
1192 retval = bxattr_exit_ok;
1196 _("llistxattr error on file \"%s\": ERR=%s\n"),
1197 jcr->last_fname, be.bstrerror());
1198 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1199 jcr->last_fname, be.bstrerror());
1207 xattr_list[xattr_list_len] = '\0';
1210 * Walk the list of extended attributes names and retrieve the data.
1211 * We already count the bytes needed for serializing the stream later on.
1213 for (bp = xattr_list;
1214 (bp - xattr_list) + 1 < xattr_list_len;
1215 bp = strchr(bp, '\0') + 1) {
1219 * On some OSes you also get the acls in the extented attribute list.
1220 * So we check if we are already backing up acls and if we do we
1221 * don't store the extended attribute with the same info.
1223 if (ff_pkt->flags & FO_ACL) {
1224 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1225 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1233 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1236 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1237 if (bstrcmp(bp, xattr_skiplist[cnt])) {
1244 name_length = strlen(bp);
1245 if (skip_xattr || name_length == 0) {
1246 Dmsg1(100, "Skipping xattr named %s\n", bp);
1251 * First see how long the value is for the extended attribute.
1253 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1254 switch (xattr_value_len) {
1260 retval = bxattr_exit_ok;
1264 _("lgetxattr error on file \"%s\": ERR=%s\n"),
1265 jcr->last_fname, be.bstrerror());
1266 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1267 jcr->last_fname, be.bstrerror());
1277 * Each xattr valuepair starts with a magic so we can parse it easier.
1279 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1280 current_xattr->magic = XATTR_MAGIC;
1281 current_xattr->value = NULL;
1282 expected_serialize_len += sizeof(current_xattr->magic);
1285 * Allocate space for storing the name.
1287 current_xattr->name_length = name_length;
1288 current_xattr->name = (char *)malloc(current_xattr->name_length);
1289 memcpy(current_xattr->name, bp, current_xattr->name_length);
1291 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1293 switch (xattr_value_len) {
1295 current_xattr->value = NULL;
1296 current_xattr->value_length = 0;
1297 expected_serialize_len += sizeof(current_xattr->value_length);
1301 * Allocate space for storing the value.
1303 current_xattr->value = (char *)malloc(xattr_value_len);
1304 memset(current_xattr->value, 0, xattr_value_len);
1306 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1307 if (xattr_value_len < 0) {
1312 retval = bxattr_exit_ok;
1316 _("lgetxattr error on file \"%s\": ERR=%s\n"),
1317 jcr->last_fname, be.bstrerror());
1318 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1319 jcr->last_fname, be.bstrerror());
1324 * Default failure path out when retrieval of attr fails.
1326 free(current_xattr->value);
1327 free(current_xattr->name);
1328 free(current_xattr);
1333 * Store the actual length of the value.
1335 current_xattr->value_length = xattr_value_len;
1336 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1340 if (xattr_value_list == NULL) {
1341 xattr_value_list = New(alist(10, not_owned_by_alist));
1344 xattr_value_list->append(current_xattr);
1348 * Protect ourself against things getting out of hand.
1350 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1352 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1353 jcr->last_fname, MAX_XATTR_STREAM);
1359 xattr_list = (char *)NULL;
1362 * If we found any xattr send them to the SD.
1364 if (xattr_count > 0) {
1366 * Serialize the datastream.
1368 if (serialize_xattr_stream(jcr,
1369 expected_serialize_len,
1370 xattr_value_list) < expected_serialize_len) {
1372 _("Failed to serialize extended attributes on file \"%s\"\n"),
1374 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1380 * Send the datastream to the SD.
1382 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1384 retval = bxattr_exit_ok;
1388 if (xattr_list != NULL) {
1391 if (xattr_value_list != NULL) {
1392 xattr_drop_internal_table(xattr_value_list);
1398 static bxattr_exit_code generic_parse_xattr_streams(JCR *jcr,
1401 uint32_t content_length)
1403 xattr_t *current_xattr;
1404 alist *xattr_value_list;
1405 bxattr_exit_code retval = bxattr_exit_error;
1407 xattr_value_list = New(alist(10, not_owned_by_alist));
1409 if (unserialize_xattr_stream(jcr,
1412 xattr_value_list) != bxattr_exit_ok) {
1416 foreach_alist(current_xattr, xattr_value_list) {
1417 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1423 case BXATTR_ENOTSUP:
1425 * If the filesystem reports it doesn't support XATTRs we clear
1426 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1427 * on all other files on the same filesystem. The
1428 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1429 * change from one filesystem to an other.
1431 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
1435 _("lsetxattr error on file \"%s\": ERR=%s\n"),
1436 jcr->last_fname, be.bstrerror());
1437 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1438 jcr->last_fname, be.bstrerror());
1444 retval = bxattr_exit_ok;
1447 xattr_drop_internal_table(xattr_value_list);
1453 * Function pointers to the build and parse function to use for these xattrs.
1455 static bxattr_exit_code (*os_build_xattr_streams)
1456 (JCR *jcr, FF_PKT *ff_pkt) =
1457 generic_xattr_build_streams;
1458 static bxattr_exit_code (*os_parse_xattr_streams)
1459 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1460 generic_parse_xattr_streams;
1462 #elif defined(HAVE_FREEBSD_OS) || \
1463 defined(HAVE_NETBSD_OS) || \
1464 defined(HAVE_OPENBSD_OS)
1466 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1467 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1468 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1469 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1470 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1471 #error "Missing full support for the extattr functions."
1474 #ifdef HAVE_SYS_EXTATTR_H
1475 #include <sys/extattr.h>
1477 #error "Missing sys/extattr.h header file"
1480 #ifdef HAVE_LIBUTIL_H
1481 #include <libutil.h>
1484 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1485 #define extattr_get_link extattr_get_file
1487 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1488 #define extattr_set_link extattr_set_file
1490 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1491 #define extattr_list_link extattr_list_file
1494 #if defined(HAVE_FREEBSD_OS)
1495 static int os_default_xattr_streams[1] = {
1496 STREAM_XATTR_FREEBSD
1498 static int os_default_xattr_namespaces[2] = {
1499 EXTATTR_NAMESPACE_USER,
1500 EXTATTR_NAMESPACE_SYSTEM
1502 static const char *xattr_acl_skiplist[4] = {
1503 "system.posix1e.acl_access",
1504 "system.posix1e.acl_default",
1508 static const char *xattr_skiplist[1] = {
1511 #elif defined(HAVE_NETBSD_OS)
1512 static int os_default_xattr_streams[1] = {
1515 static int os_default_xattr_namespaces[2] = {
1516 EXTATTR_NAMESPACE_USER,
1517 EXTATTR_NAMESPACE_SYSTEM
1519 static const char *xattr_acl_skiplist[1] = {
1522 static const char *xattr_skiplist[1] = {
1525 #elif defined(HAVE_OPENBSD_OS)
1526 static int os_default_xattr_streams[1] = {
1527 STREAM_XATTR_OPENBSD
1529 static int os_default_xattr_namespaces[2] = {
1530 EXTATTR_NAMESPACE_USER,
1531 EXTATTR_NAMESPACE_SYSTEM
1533 static const char *xattr_acl_skiplist[1] = {
1536 static const char *xattr_skiplist[1] = {
1541 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1544 char *xattr_list = NULL;
1545 int cnt, index, xattr_count = 0;
1546 int32_t xattr_list_len,
1548 uint32_t expected_serialize_len = 0;
1549 unsigned int namespace_index;
1551 char *current_attrnamespace = NULL;
1552 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1553 xattr_t *current_xattr;
1554 alist *xattr_value_list = NULL;
1555 bxattr_exit_code retval = bxattr_exit_error;
1558 * Loop over all available xattr namespaces.
1560 for (namespace_index = 0;
1561 namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int);
1562 namespace_index++) {
1563 attrnamespace = os_default_xattr_namespaces[namespace_index];
1566 * First get the length of the available list with extended attributes.
1567 * If we get EPERM on system namespace, don't return error.
1568 * This is expected for normal users trying to archive the system
1569 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1570 * they've decided to return EOPNOTSUPP instead.
1572 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1573 switch (xattr_list_len) {
1579 retval = bxattr_exit_ok;
1581 #if defined(EOPNOTSUPP)
1585 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1593 _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1594 jcr->last_fname, be.bstrerror());
1595 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1596 jcr->last_fname, be.bstrerror());
1608 * Allocate room for the extented attribute list.
1610 xattr_list = (char *)malloc(xattr_list_len + 1);
1611 memset(xattr_list, 0, xattr_list_len + 1);
1614 * Get the actual list of extended attributes names for a file.
1616 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace,
1617 xattr_list, xattr_list_len);
1618 switch (xattr_list_len) {
1624 retval = bxattr_exit_ok;
1628 _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1629 jcr->last_fname, be.bstrerror());
1630 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1631 jcr->last_fname, be.bstrerror());
1639 xattr_list[xattr_list_len] = '\0';
1642 * Convert the numeric attrnamespace into a string representation and make
1643 * a private copy of that string. The extattr_namespace_to_string functions
1644 * returns a strdupped string which we need to free.
1646 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1648 _("Failed to convert %d into namespace on file \"%s\"\n"),
1649 attrnamespace, jcr->last_fname);
1650 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1651 attrnamespace, jcr->last_fname);
1656 * Walk the list of extended attributes names and retrieve the data.
1657 * We already count the bytes needed for serializing the stream later on.
1659 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1663 * Print the current name into the buffer as its not null terminated
1664 * we need to use the length encoded in the string for copying only
1667 cnt = xattr_list[index];
1668 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1669 cnt = ((int)sizeof(current_attrname) - 1);
1671 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1672 current_attrname[cnt] = '\0';
1675 * First make a xattr tuple of the current namespace and the name of
1676 * the xattr. e.g. something like user.<attrname> or system.<attrname>
1678 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s",
1679 current_attrnamespace, current_attrname);
1682 * On some OSes you also get the acls in the extented attribute list.
1683 * So we check if we are already backing up acls and if we do we
1684 * don't store the extended attribute with the same info.
1686 if (ff_pkt->flags & FO_ACL) {
1687 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1688 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1696 * On some OSes we want to skip certain xattrs which are in the
1697 * xattr_skiplist array.
1700 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1701 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1709 Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1714 * First see how long the value is for the extended attribute.
1716 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1717 current_attrname, NULL, 0);
1718 switch (xattr_value_len) {
1724 retval = bxattr_exit_ok;
1728 _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1729 jcr->last_fname, be.bstrerror());
1730 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1731 jcr->last_fname, be.bstrerror());
1741 * Each xattr valuepair starts with a magic so we can parse it easier.
1743 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1744 current_xattr->magic = XATTR_MAGIC;
1745 current_xattr->value = NULL;
1746 expected_serialize_len += sizeof(current_xattr->magic);
1749 * Allocate space for storing the name.
1751 current_xattr->name_length = strlen(current_attrtuple);
1752 current_xattr->name = (char *)malloc(current_xattr->name_length);
1753 memcpy(current_xattr->name, current_attrtuple, current_xattr->name_length);
1755 expected_serialize_len += sizeof(current_xattr->name_length) +
1756 current_xattr->name_length;
1758 switch (xattr_value_len) {
1760 current_xattr->value = NULL;
1761 current_xattr->value_length = 0;
1762 expected_serialize_len += sizeof(current_xattr->value_length);
1766 * Allocate space for storing the value.
1768 current_xattr->value = (char *)malloc(xattr_value_len);
1769 memset(current_xattr->value, 0, xattr_value_len);
1771 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1772 current_attrname, current_xattr->value,
1774 if (xattr_value_len < 0) {
1779 retval = bxattr_exit_ok;
1783 _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1784 jcr->last_fname, be.bstrerror());
1785 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1786 jcr->last_fname, be.bstrerror());
1791 * Default failure path out when retrieval of attr fails.
1793 free(current_xattr->value);
1794 free(current_xattr->name);
1795 free(current_xattr);
1800 * Store the actual length of the value.
1802 current_xattr->value_length = xattr_value_len;
1803 expected_serialize_len += sizeof(current_xattr->value_length) +
1804 current_xattr->value_length;
1808 if (xattr_value_list == NULL) {
1809 xattr_value_list = New(alist(10, not_owned_by_alist));
1812 xattr_value_list->append(current_xattr);
1816 * Protect ourself against things getting out of hand.
1818 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1820 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1821 jcr->last_fname, MAX_XATTR_STREAM);
1827 * Drop the local copy of the current_attrnamespace.
1829 actuallyfree(current_attrnamespace);
1830 current_attrnamespace = NULL;
1833 * We are done with this xattr list.
1836 xattr_list = (char *)NULL;
1840 * If we found any xattr send them to the SD.
1842 if (xattr_count > 0) {
1844 * Serialize the datastream.
1846 if (serialize_xattr_stream(jcr,
1847 expected_serialize_len,
1848 xattr_value_list) < expected_serialize_len) {
1850 _("Failed to serialize extended attributes on file \"%s\"\n"),
1852 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1858 * Send the datastream to the SD.
1860 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1862 retval = bxattr_exit_ok;
1866 if (current_attrnamespace != NULL) {
1867 actuallyfree(current_attrnamespace);
1869 if (xattr_list != NULL) {
1872 if (xattr_value_list != NULL) {
1873 xattr_drop_internal_table(xattr_value_list);
1879 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr,
1882 uint32_t content_length)
1884 xattr_t *current_xattr;
1885 alist *xattr_value_list;
1886 int current_attrnamespace, cnt;
1887 char *attrnamespace, *attrname;
1888 bxattr_exit_code retval = bxattr_exit_error;
1890 xattr_value_list = New(alist(10, not_owned_by_alist));
1892 if (unserialize_xattr_stream(jcr,
1895 xattr_value_list) != bxattr_exit_ok) {
1899 foreach_alist(current_xattr, xattr_value_list) {
1901 * Try splitting the xattr_name into a namespace and name part.
1902 * The splitting character is a .
1904 attrnamespace = current_xattr->name;
1905 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1907 _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1908 current_xattr->name, jcr->last_fname);
1909 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1910 current_xattr->name, jcr->last_fname);
1916 * Make sure the attrnamespace makes sense.
1918 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1920 _("Failed to convert %s into namespace on file \"%s\"\n"),
1921 attrnamespace, jcr->last_fname);
1922 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1923 attrnamespace, jcr->last_fname);
1928 * Try restoring the extended attribute.
1930 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1931 attrname, current_xattr->value, current_xattr->value_length);
1932 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1941 _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1942 jcr->last_fname, be.bstrerror());
1943 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1944 jcr->last_fname, be.bstrerror());
1951 retval = bxattr_exit_ok;
1954 xattr_drop_internal_table(xattr_value_list);
1960 * Function pointers to the build and parse function to use for these xattrs.
1962 static bxattr_exit_code (*os_build_xattr_streams)
1963 (JCR *jcr, FF_PKT *ff_pkt) =
1964 bsd_build_xattr_streams;
1965 static bxattr_exit_code (*os_parse_xattr_streams)
1966 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1967 bsd_parse_xattr_streams;
1969 #elif defined(HAVE_OSF1_OS)
1971 #if !defined(HAVE_GETPROPLIST) || \
1972 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1973 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1974 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1975 !defined(HAVE_SETPROPLIST)
1976 #error "Missing full support for the Extended Attributes functions."
1979 #ifdef HAVE_SYS_PROPLIST_H
1980 #include <sys/proplist.h>
1982 #error "Missing sys/proplist.h header file"
1986 * Define the supported XATTR streams for this OS
1988 static int os_default_xattr_streams[1] = {
1991 static const char *xattr_acl_skiplist[1] = {
1994 static const char *xattr_skiplist[1] = {
1998 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2005 int xattr_count = 0;
2008 int32_t xattr_list_len,
2011 uint32_t expected_serialize_len = 0;
2012 xattr_t *current_xattr;
2013 alist *xattr_value_list = NULL;
2014 struct proplistname_args prop_args;
2015 bxattr_exit_code retval = bxattr_exit_error;
2016 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
2018 xattrbuf_size = sizeof_pool_memory(xattrbuf);
2019 xattrbuf_min_size = 0;
2020 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
2021 xattrbuf, &xattrbuf_min_size);
2024 * See what xattr are available.
2026 switch (xattr_list_len) {
2033 * If the filesystem reports it doesn't support XATTRs we clear
2034 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
2035 * on all other files on the same filesystem. The
2036 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
2037 * change from one filesystem to an other.
2039 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
2040 retval = bxattr_exit_ok;
2044 _("getproplist error on file \"%s\": ERR=%s\n"),
2045 jcr->last_fname, be.bstrerror());
2046 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
2047 jcr->last_fname, be.bstrerror());
2053 if (xattrbuf_min_size) {
2055 * The buffer isn't big enough to hold the xattr data, we now have
2056 * a minimum buffersize so we resize the buffer and try again.
2058 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
2059 xattrbuf_size = xattrbuf_min_size + 1;
2060 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
2061 xattrbuf, &xattrbuf_min_size);
2062 switch (xattr_list_len) {
2069 _("getproplist error on file \"%s\": ERR=%s\n"),
2070 jcr->last_fname, be.bstrerror());
2071 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
2072 jcr->last_fname, be.bstrerror());
2079 * This should never happen as we sized the buffer according to the minimumsize
2080 * returned by a previous getproplist call. If it does happen things are fishy and
2081 * we are better of forgetting this xattr as it seems its list is changing at this
2082 * exact moment so we can never make a good backup copy of it.
2084 retval = bxattr_exit_ok;
2093 retval = bxattr_exit_ok;
2102 * Walk the list of extended attributes names and retrieve the data.
2103 * We already count the bytes needed for serializing the stream later on.
2106 while (xattrbuf_size > 0) {
2108 * Call getproplist_entry to initialize name and value
2109 * pointers to entries position within buffer.
2111 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
2114 * On some OSes you also get the acls in the extented attribute list.
2115 * So we check if we are already backing up acls and if we do we
2116 * don't store the extended attribute with the same info.
2118 if (ff_pkt->flags & FO_ACL) {
2119 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
2120 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
2128 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
2131 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
2132 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
2140 Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
2145 * Each xattr valuepair starts with a magic so we can parse it easier.
2147 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
2148 current_xattr->magic = XATTR_MAGIC;
2149 expected_serialize_len += sizeof(current_xattr->magic);
2151 current_xattr->name_length = strlen(xattr_name);
2152 current_xattr->name = bstrdup(xattr_name);
2154 expected_serialize_len += sizeof(current_xattr->name_length) +
2155 current_xattr->name_length;
2157 current_xattr->value_length = *xattr_value_len;
2158 current_xattr->value = (char *)malloc(current_xattr->value_length);
2159 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
2161 expected_serialize_len += sizeof(current_xattr->value_length) +
2162 current_xattr->value_length;
2164 if (xattr_value_list == NULL) {
2165 xattr_value_list = New(alist(10, not_owned_by_alist));
2168 xattr_value_list->append(current_xattr);
2172 * Protect ourself against things getting out of hand.
2174 if (expected_serialize_len >= MAX_XATTR_STREAM) {
2176 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2177 jcr->last_fname, MAX_XATTR_STREAM);
2183 * If we found any xattr send them to the SD.
2185 if (xattr_count > 0) {
2187 * Serialize the datastream.
2189 if (serialize_xattr_stream(jcr,
2190 expected_serialize_len,
2191 xattr_value_list) < expected_serialize_len) {
2193 _("Failed to serialize extended attributes on file \"%s\"\n"),
2195 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
2201 * Send the datastream to the SD.
2203 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
2205 retval = bxattr_exit_ok;
2209 if (xattr_value_list != NULL) {
2210 xattr_drop_internal_table(xattr_value_list);
2212 free_pool_memory(xattrbuf);
2217 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr,
2220 uint32_t content_length)
2222 char *bp, *xattrbuf = NULL;
2223 int32_t xattrbuf_size, cnt;
2224 xattr_t *current_xattr;
2225 alist *xattr_value_list;
2226 bxattr_exit_code retval = bxattr_exit_error;
2228 xattr_value_list = New(alist(10, not_owned_by_alist));
2230 if (unserialize_xattr_stream(jcr,
2233 xattr_value_list) != bxattr_exit_ok) {
2238 * See how big the propertylist must be.
2241 foreach_alist(current_xattr, xattr_value_list) {
2242 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
2245 xattrbuf = (char *)malloc(xattrbuf_size);
2248 * Add all value pairs to the proplist.
2252 foreach_alist(current_xattr, xattr_value_list) {
2253 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
2254 current_xattr->value, &bp);
2260 if (cnt != xattrbuf_size) {
2262 _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
2264 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
2270 * Restore the list of extended attributes on the file.
2272 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
2280 * If the filesystem reports it doesn't support XATTRs we clear
2281 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
2282 * on all other files on the same filesystem. The
2283 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
2284 * change from one filesystem to an other.
2286 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
2287 retval = bxattr_exit_ok;
2291 _("setproplist error on file \"%s\": ERR=%s\n"),
2292 jcr->last_fname, be.bstrerror());
2293 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
2294 jcr->last_fname, be.bstrerror());
2303 retval = bxattr_exit_ok;
2309 xattr_drop_internal_table(xattr_value_list);
2315 * Function pointers to the build and parse function to use for these xattrs.
2317 static bxattr_exit_code (*os_build_xattr_streams)
2318 (JCR *jcr, FF_PKT *ff_pkt) =
2319 tru64_build_xattr_streams;
2320 static bxattr_exit_code (*os_parse_xattr_streams)
2321 (JCR *jcr, int stream, char *content, uint32_t content_length) =
2322 tru64_parse_xattr_streams;
2324 #elif defined(HAVE_SUN_OS)
2326 * Solaris extended attributes were introduced in Solaris 9
2329 * Solaris extensible attributes were introduced in OpenSolaris
2330 * by PSARC 2007/315 Solaris extensible attributes are also
2331 * sometimes called extended system attributes.
2333 * man fsattr(5) on Solaris gives a wealth of info. The most
2334 * important bits are:
2336 * Attributes are logically supported as files within the file
2337 * system. The file system is therefore augmented with an
2338 * orthogonal name space of file attributes. Any file (includ-
2339 * ing attribute files) can have an arbitrarily deep attribute
2340 * tree associated with it. Attribute values are accessed by
2341 * file descriptors obtained through a special attribute inter-
2342 * face. This logical view of "attributes as files" allows the
2343 * leveraging of existing file system interface functionality
2344 * to support the construction, deletion, and manipulation of
2347 * The special files "." and ".." retain their accustomed
2348 * semantics within the attribute hierarchy. The "." attribute
2349 * file refers to the current directory and the ".." attribute
2350 * file refers to the parent directory. The unnamed directory
2351 * at the head of each attribute tree is considered the "child"
2352 * of the file it is associated with and the ".." file refers
2353 * to the associated file. For any non-directory file with
2354 * attributes, the ".." entry in the unnamed directory refers
2355 * to a file that is not a directory.
2357 * Conceptually, the attribute model is fully general. Extended
2358 * attributes can be any type of file (doors, links, direc-
2359 * tories, and so forth) and can even have their own attributes
2360 * (fully recursive). As a result, the attributes associated
2361 * with a file could be an arbitrarily deep directory hierarchy
2362 * where each attribute could have an equally complex attribute
2363 * tree associated with it. Not all implementations are able
2364 * to, or want to, support the full model. Implementation are
2365 * therefore permitted to reject operations that are not sup-
2366 * ported. For example, the implementation for the UFS file
2367 * system allows only regular files as attributes (for example,
2368 * no sub-directories) and rejects attempts to place attributes
2371 * The following list details the operations that are rejected
2372 * in the current implementation:
2374 * link Any attempt to create links between
2375 * attribute and non-attribute space
2376 * is rejected to prevent security-
2377 * related or otherwise sensitive
2378 * attributes from being exposed, and
2379 * therefore manipulable, as regular
2382 * rename Any attempt to rename between
2383 * attribute and non-attribute space
2384 * is rejected to prevent an already
2385 * linked file from being renamed and
2386 * thereby circumventing the link res-
2389 * mkdir, symlink, mknod Any attempt to create a "non-
2390 * regular" file in attribute space is
2391 * rejected to reduce the functional-
2392 * ity, and therefore exposure and
2393 * risk, of the initial implementa-
2396 * The entire available name space has been allocated to "gen-
2397 * eral use" to bring the implementation in line with the NFSv4
2398 * draft standard [NFSv4]. That standard defines "named attri-
2399 * butes" (equivalent to Solaris Extended Attributes) with no
2400 * naming restrictions. All Sun applications making use of
2401 * opaque extended attributes will use the prefix "SUNW".
2404 #ifdef HAVE_SYS_ATTR_H
2405 #include <sys/attr.h>
2412 #ifdef HAVE_SYS_NVPAIR_H
2413 #include <sys/nvpair.h>
2416 #ifdef HAVE_SYS_ACL_H
2417 #include <sys/acl.h>
2420 #if !defined(HAVE_OPENAT) || \
2421 !defined(HAVE_UNLINKAT) || \
2422 !defined(HAVE_FCHOWNAT) || \
2423 !defined(HAVE_FUTIMESAT)
2424 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2428 * Define the supported XATTR streams for this OS
2430 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2431 static int os_default_xattr_streams[2] = {
2432 STREAM_XATTR_SOLARIS,
2433 STREAM_XATTR_SOLARIS_SYS
2436 static int os_default_xattr_streams[1] = {
2437 STREAM_XATTR_SOLARIS
2439 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2442 * This code creates a temporary cache with entries for each xattr which has
2443 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2445 static inline xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2447 xattr_link_cache_entry_t *ptr;
2449 foreach_alist(ptr, jcr->xattr_data->u.build->link_cache) {
2450 if (ptr && ptr->inum == inum) {
2457 static inline void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2459 xattr_link_cache_entry_t *ptr;
2461 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2462 memset(ptr, 0, sizeof(xattr_link_cache_entry_t));
2464 ptr->target = bstrdup(target);
2466 if (!jcr->xattr_data->u.build->link_cache) {
2467 jcr->xattr_data->u.build->link_cache = New(alist(10, not_owned_by_alist));
2469 jcr->xattr_data->u.build->link_cache->append(ptr);
2472 static inline void drop_xattr_link_cache(JCR *jcr)
2474 xattr_link_cache_entry_t *ptr;
2477 * Walk the list of xattr link cache entries and free allocated memory on traversing.
2479 foreach_alist(ptr, jcr->xattr_data->u.build->link_cache) {
2484 delete jcr->xattr_data->u.build->link_cache;
2485 jcr->xattr_data->u.build->link_cache = NULL;
2488 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2490 * This function returns true if a non default extended system attribute
2491 * list is associated with fd and returns false when an error has occured
2492 * or when only extended system attributes other than archive,
2493 * av_modified or crtime are set.
2495 * The function returns true for the following cases:
2497 * - any extended system attribute other than the default attributes
2498 * ('archive', 'av_modified' and 'crtime') is set
2499 * - nvlist has NULL name string
2500 * - nvpair has data type of 'nvlist'
2501 * - default data type.
2503 static bool solaris_has_non_transient_extensible_attributes(int fd)
2511 bool retval = false;
2513 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2518 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2519 name = nvpair_name(pair);
2522 fattr = name_to_attr(name);
2528 type = nvpair_type(pair);
2530 case DATA_TYPE_BOOLEAN_VALUE:
2531 if (nvpair_value_boolean_value(pair, &value) != 0) {
2534 if (value && fattr != F_ARCHIVE &&
2535 fattr != F_AV_MODIFIED) {
2540 case DATA_TYPE_UINT64_ARRAY:
2541 if (fattr != F_CRTIME) {
2546 case DATA_TYPE_NVLIST:
2554 if (response != NULL) {
2555 nvlist_free(response);
2559 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2561 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2563 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2564 * There is no need to store those acls as we already store the stat bits too.
2566 static bool acl_is_trivial(int count, aclent_t *entries)
2571 for (n = 0; n < count; n++) {
2573 if (!(ace->a_type == USER_OBJ ||
2574 ace->a_type == GROUP_OBJ ||
2575 ace->a_type == OTHER_OBJ ||
2576 ace->a_type == CLASS_OBJ))
2581 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2583 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2585 bxattr_exit_code retval = bxattr_exit_error;
2587 #ifdef HAVE_EXTENDED_ACL
2592 * See if this attribute has an ACL
2594 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2595 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2597 * See if there is a non trivial acl on the file.
2599 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2600 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2605 retval = bxattr_exit_ok;
2609 _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2610 attrname, jcr->last_fname, be.bstrerror());
2611 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2612 attrname, jcr->last_fname, be.bstrerror());
2618 #if defined(ACL_SID_FMT)
2620 * New format flag added in newer Solaris versions.
2622 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2624 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2625 #endif /* ACL_SID_FMT */
2627 *acl_text = acl_totext(aclp, flags);
2635 retval = bxattr_exit_ok;
2636 #else /* HAVE_EXTENDED_ACL */
2638 aclent_t *acls = NULL;
2641 * See if this attribute has an ACL
2644 n = facl(fd, GETACLCNT, 0, NULL);
2646 n = acl(attrname, GETACLCNT, 0, NULL);
2649 if (n >= MIN_ACL_ENTRIES) {
2650 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2651 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2652 acl(attrname, GETACL, n, acls) != n) {
2658 retval = bxattr_exit_ok;
2662 _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2663 attrname, jcr->last_fname, be.bstrerror());
2664 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2665 attrname, jcr->last_fname, be.bstrerror());
2672 * See if there is a non trivial acl on the file.
2674 if (!acl_is_trivial(n, acls)) {
2675 if ((*acl_text = acltotext(acls, n)) == NULL) {
2679 _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2680 attrname, jcr->last_fname, be.bstrerror());
2681 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2682 attrname, jcr->last_fname, be.bstrerror());
2694 retval = bxattr_exit_ok;
2695 #endif /* HAVE_EXTENDED_ACL */
2697 #else /* HAVE_ACL */
2698 retval = bxattr_exit_ok;
2699 #endif /* HAVE_ACL */
2706 * Forward declaration for recursive function call.
2708 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2711 * Save an extended or extensible attribute.
2712 * This is stored as an opaque stream of bytes with the following encoding:
2714 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2716 * or for a hardlinked or symlinked attribute
2718 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2720 * xattr_name can be a subpath relative to the file the xattr is on.
2721 * stat_buffer is the string representation of the stat struct.
2722 * acl_string is an acl text when a non trivial acl is set on the xattr.
2723 * actual_xattr_data is the content of the xattr file.
2725 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2726 const char *attrname, bool toplevel_hidden_dir, int stream)
2731 xattr_link_cache_entry_t *xlce;
2732 char target_attrname[PATH_MAX];
2733 char link_source[PATH_MAX];
2734 char *acl_text = NULL;
2735 char attribs[MAXSTRING];
2736 char buffer[XATTR_BUFSIZ];
2737 bxattr_exit_code retval = bxattr_exit_error;
2739 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2742 * Get the stats of the extended or extensible attribute.
2744 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2749 retval = bxattr_exit_ok;
2753 _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2754 target_attrname, jcr->last_fname, be.bstrerror());
2755 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2756 target_attrname, jcr->last_fname, be.bstrerror());
2762 * Based on the filetype perform the correct action. We support most filetypes here, more
2763 * then the actual implementation on Solaris supports so some code may never get executed
2764 * due to limitations in the implementation.
2766 switch (st.st_mode & S_IFMT) {
2771 * Get any acl on the xattr.
2773 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2777 * The current implementation of xattr on Solaris doesn't support this,
2778 * but if it ever does we are prepared.
2779 * Encode the stat struct into an ASCII representation.
2781 encode_stat(attribs, &st, sizeof(st), 0, stream);
2782 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2783 target_attrname, 0, attribs, 0,
2784 (acl_text) ? acl_text : "", 0);
2788 * Get any acl on the xattr.
2790 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2794 * See if this is the toplevel_hidden_dir being saved.
2796 if (toplevel_hidden_dir) {
2798 * Save the data for later storage when we encounter a real xattr.
2799 * We store the data in the jcr->xattr_data->u.build->content buffer
2800 * and flush that just before sending out the first real xattr.
2801 * Encode the stat struct into an ASCII representation and jump
2802 * out of the function.
2804 encode_stat(attribs, &st, sizeof(st), 0, stream);
2805 cnt = bsnprintf(buffer, sizeof(buffer),
2807 target_attrname, 0, attribs, 0,
2808 (acl_text) ? acl_text : "", 0);
2809 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2810 jcr->xattr_data->u.build->content_length = cnt;
2814 * The current implementation of xattr on Solaris doesn't support this,
2815 * but if it ever does we are prepared.
2816 * Encode the stat struct into an ASCII representation.
2818 encode_stat(attribs, &st, sizeof(st), 0, stream);
2819 cnt = bsnprintf(buffer, sizeof(buffer),
2821 target_attrname, 0, attribs, 0,
2822 (acl_text) ? acl_text : "", 0);
2827 * If this is a hardlinked file check the inode cache for a hit.
2829 if (st.st_nlink > 1) {
2831 * See if the cache already knows this inode number.
2833 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2835 * Generate a xattr encoding with the reference to the target in there.
2837 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2838 cnt = bsnprintf(buffer, sizeof(buffer),
2840 target_attrname, 0, attribs, 0, xlce->target, 0);
2841 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2842 jcr->xattr_data->u.build->content_length = cnt;
2843 retval = send_xattr_stream(jcr, stream);
2846 * For a hard linked file we are ready now, no need to recursively
2847 * save the attributes.
2853 * Store this hard linked file in the cache.
2854 * Store the name relative to the top level xattr space.
2856 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2860 * Get any acl on the xattr.
2862 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2867 * Encode the stat struct into an ASCII representation.
2869 encode_stat(attribs, &st, sizeof(st), 0, stream);
2870 cnt = bsnprintf(buffer, sizeof(buffer),
2872 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2875 * Open the extended or extensible attribute file.
2877 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2882 retval = bxattr_exit_ok;
2886 _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2887 target_attrname, jcr->last_fname, be.bstrerror());
2888 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2889 target_attrname, jcr->last_fname, be.bstrerror());
2896 * The current implementation of xattr on Solaris doesn't support this, but if it
2897 * ever does we are prepared.
2898 * Encode the stat struct into an ASCII representation.
2900 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2905 retval = bxattr_exit_ok;
2909 _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2910 target_attrname, jcr->last_fname, be.bstrerror());
2911 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2912 target_attrname, jcr->last_fname, be.bstrerror());
2918 * Generate a xattr encoding with the reference to the target in there.
2920 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2921 cnt = bsnprintf(buffer, sizeof(buffer),
2923 target_attrname, 0, attribs, 0, link_source, 0);
2924 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2925 jcr->xattr_data->u.build->content_length = cnt;
2926 retval = send_xattr_stream(jcr, stream);
2928 if (retval == bxattr_exit_ok) {
2929 jcr->xattr_data->u.build->nr_saved++;
2933 * For a soft linked file we are ready now, no need to recursively save the attributes.
2941 * See if this is the first real xattr being saved.
2942 * If it is save the toplevel_hidden_dir attributes first.
2943 * This is easy as its stored already in the
2944 * jcr->xattr_data->u.build->content buffer.
2946 if (jcr->xattr_data->u.build->nr_saved == 0) {
2947 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2948 if (retval != bxattr_exit_ok) {
2951 jcr->xattr_data->u.build->nr_saved++;
2954 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2955 jcr->xattr_data->u.build->content_length = cnt;
2958 * Only dump the content of regular files.
2960 switch (st.st_mode & S_IFMT) {
2962 if (st.st_size > 0) {
2964 * Protect ourself against things getting out of hand.
2966 if (st.st_size >= MAX_XATTR_STREAM) {
2968 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2969 jcr->last_fname, MAX_XATTR_STREAM);
2973 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2974 jcr->xattr_data->u.build->content =
2975 check_pool_memory_size(jcr->xattr_data->u.build->content,
2976 jcr->xattr_data->u.build->content_length + cnt);
2977 memcpy(jcr->xattr_data->u.build->content +
2978 jcr->xattr_data->u.build->content_length, buffer, cnt);
2979 jcr->xattr_data->u.build->content_length += cnt;
2984 _("Unable to read content of xattr %s on file \"%s\"\n"),
2985 target_attrname, jcr->last_fname);
2986 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2987 target_attrname, jcr->last_fname);
2998 * We build a new xattr stream send it to the SD.
3000 retval = send_xattr_stream(jcr, stream);
3001 if (retval != bxattr_exit_ok) {
3004 jcr->xattr_data->u.build->nr_saved++;
3007 * Recursivly call solaris_save_extended_attributes for archiving the attributes
3008 * available on this extended attribute.
3010 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
3013 * The recursive call could change our working dir so change back to the wanted workdir.
3015 if (fchdir(fd) < 0) {
3020 retval = bxattr_exit_ok;
3024 _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
3025 jcr->last_fname, be.bstrerror());
3026 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
3027 jcr->last_fname, fd, be.bstrerror());
3033 if (acl_text != NULL) {
3042 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
3045 int fd, filefd = -1, attrdirfd = -1;
3048 char current_xattr_namespace[PATH_MAX];
3049 bxattr_exit_code retval = bxattr_exit_error;
3052 * Determine what argument to use. Use attr_parent when set
3053 * (recursive call) or jcr->last_fname for first call. Also save
3054 * the current depth of the xattr_space we are in.
3058 if (xattr_namespace) {
3059 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
3060 xattr_namespace, attr_parent);
3062 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
3065 name = jcr->last_fname;
3066 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
3070 * Open the file on which to save the xattrs read-only.
3072 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
3077 retval = bxattr_exit_ok;
3081 _("Unable to open file \"%s\": ERR=%s\n"),
3082 jcr->last_fname, be.bstrerror());
3083 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
3084 jcr->last_fname, be.bstrerror());
3090 * Open the xattr naming space.
3092 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3098 * Gentile way of the system saying this type of xattr layering is not supported.
3099 * Which is not problem we just forget about this this xattr.
3100 * But as this is not an error we return a positive return value.
3102 retval = bxattr_exit_ok;
3105 retval = bxattr_exit_ok;
3109 _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
3110 name, jcr->last_fname, be.bstrerror());
3111 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
3112 name, jcr->last_fname, be.bstrerror());
3118 * We need to change into the attribute directory to determine if each of the
3119 * attributes should be saved.
3121 if (fchdir(attrdirfd) < 0) {
3125 _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3126 jcr->last_fname, be.bstrerror());
3127 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
3128 jcr->last_fname, attrdirfd, be.bstrerror());
3133 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
3134 * else because the readdir returns "." entry after the extensible attr entry.
3135 * And as we want this entry before anything else we better just save its data.
3138 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
3139 true, STREAM_XATTR_SOLARIS);
3141 if ((fd = dup(attrdirfd)) == -1 ||
3142 (dirp = fdopendir(fd)) == (DIR *)NULL) {
3146 _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
3147 jcr->last_fname, be.bstrerror());
3148 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
3149 jcr->last_fname, fd, be.bstrerror());
3155 * Walk the namespace.
3157 while ((dp = readdir(dirp)) != NULL) {
3159 * Skip only the toplevel . dir.
3161 if (!attr_parent && bstrcmp(dp->d_name, "."))
3165 * Skip all .. directories
3167 if (bstrcmp(dp->d_name, ".."))
3170 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
3171 current_xattr_namespace, dp->d_name, jcr->last_fname);
3173 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3175 * We are not interested in read-only extensible attributes.
3177 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
3178 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
3179 current_xattr_namespace, dp->d_name, jcr->last_fname);
3185 * We are only interested in read-write extensible attributes
3186 * when they contain non-transient values.
3188 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
3190 * Determine if there are non-transient system attributes at the toplevel.
3191 * We need to provide a fd to the open file.
3193 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
3194 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
3195 current_xattr_namespace, dp->d_name, jcr->last_fname);
3202 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3203 false, STREAM_XATTR_SOLARIS_SYS);
3206 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
3211 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3212 false, STREAM_XATTR_SOLARIS);
3216 retval = bxattr_exit_ok;
3219 if (attrdirfd != -1)
3227 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr,
3229 const char *attrname,
3232 #ifdef HAVE_EXTENDED_ACL
3236 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
3238 _("Unable to convert acl from text on file \"%s\"\n"),
3240 return bxattr_exit_error;
3243 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
3244 acl_set(attrname, aclp) != 0) {
3248 _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3249 attrname, jcr->last_fname, be.bstrerror());
3250 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3251 attrname, jcr->last_fname, be.bstrerror());
3252 return bxattr_exit_error;
3258 return bxattr_exit_ok;
3260 #else /* HAVE_EXTENDED_ACL */
3262 aclent_t *acls = NULL;
3264 acls = aclfromtext(acl_text, &n);
3266 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
3267 acl(attrname, SETACL, n, acls) != 0) {
3271 _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3272 attrname, jcr->last_fname, be.bstrerror());
3273 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3274 attrname, jcr->last_fname, be.bstrerror());
3275 return bxattr_exit_error;
3282 return bxattr_exit_ok;
3284 #endif /* HAVE_EXTENDED_ACL */
3287 #endif /* HAVE_ACL */
3289 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr,
3292 uint32_t content_length)
3295 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
3296 int used_bytes, cnt;
3297 char *bp, *target_attrname, *attribs;
3298 char *linked_target = NULL;
3299 char *acl_text = NULL;
3303 struct timeval times[2];
3304 bxattr_exit_code retval = bxattr_exit_error;
3307 * Parse the xattr stream. First the part that is the same for all xattrs.
3312 * The name of the target xattr has a leading / we are not interested
3313 * in that so skip it when decoding the string. We always start a the /
3314 * of the xattr space anyway.
3316 target_attrname = content + 1;
3317 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
3318 (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3324 * Open the file on which to restore the xattrs read-only.
3326 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
3330 _("Unable to open file \"%s\": ERR=%s\n"),
3331 jcr->last_fname, be.bstrerror());
3332 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
3333 jcr->last_fname, be.bstrerror());
3338 * Open the xattr naming space and make it the current working dir.
3340 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3344 _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
3345 jcr->last_fname, be.bstrerror());
3346 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
3347 jcr->last_fname, be.bstrerror());
3351 if (fchdir(attrdirfd) < 0) {
3355 _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3356 jcr->last_fname, be.bstrerror());
3357 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
3358 jcr->last_fname, attrdirfd, be.bstrerror());
3363 * Try to open the correct xattr subdir based on the target_attrname given.
3364 * e.g. check if its a subdir attrname. Each / in the string makes us go
3367 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
3370 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
3374 _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3375 target_attrname, jcr->last_fname, be.bstrerror());
3376 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3377 target_attrname, jcr->last_fname, be.bstrerror());
3385 * Open the xattr naming space.
3387 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3391 _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
3392 target_attrname, jcr->last_fname, be.bstrerror());
3393 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
3394 target_attrname, jcr->last_fname, be.bstrerror());
3402 * Make the xattr space our current workingdir.
3404 if (fchdir(attrdirfd) < 0) {
3408 _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
3409 target_attrname, jcr->last_fname, be.bstrerror());
3410 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
3411 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
3415 target_attrname = ++bp;
3419 * Decode the attributes from the stream.
3421 decode_stat(attribs, &st, sizeof(st), &inum);
3424 * Decode the next field (acl_text).
3426 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
3427 (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3433 * Based on the filetype perform the correct action. We support most filetypes here, more
3434 * then the actual implementation on Solaris supports so some code may never get executed
3435 * due to limitations in the implementation.
3437 switch (st.st_mode & S_IFMT) {
3440 * The current implementation of xattr on Solaris doesn't support this,
3441 * but if it ever does we are prepared.
3443 unlinkat(attrdirfd, target_attrname, 0);
3444 if (mkfifo(target_attrname, st.st_mode) < 0) {
3448 _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3449 target_attrname, jcr->last_fname, be.bstrerror());
3450 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
3451 target_attrname, jcr->last_fname, be.bstrerror());
3458 * The current implementation of xattr on Solaris doesn't support this,
3459 * but if it ever does we are prepared.
3461 unlinkat(attrdirfd, target_attrname, 0);
3462 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3466 _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3467 target_attrname, jcr->last_fname, be.bstrerror());
3468 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3469 target_attrname, jcr->last_fname, be.bstrerror());
3475 * If its not the hidden_dir create the entry.
3476 * The current implementation of xattr on Solaris doesn't support this,
3477 * but if it ever does we are prepared.
3479 if (!bstrcmp(target_attrname, ".")) {
3480 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3481 if (mkdir(target_attrname, st.st_mode) < 0) {
3484 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3485 target_attrname, jcr->last_fname, be.bstrerror());
3486 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3487 target_attrname, jcr->last_fname, be.bstrerror());
3494 * See if this is a hard linked file. e.g. inum != 0
3499 unlinkat(attrdirfd, target_attrname, 0);
3500 if (link(linked_target, target_attrname) < 0) {
3504 _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3505 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3506 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3507 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3512 * Successfully restored xattr.
3514 retval = bxattr_exit_ok;
3517 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3518 (used_bytes = (bp - content)) >= (int32_t)content_length) {
3522 if (used_bytes < (int32_t)(content_length - 1))
3526 * Restore the actual xattr.
3528 if (!is_extensible) {
3529 unlinkat(attrdirfd, target_attrname, 0);
3532 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3536 _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3537 target_attrname, jcr->last_fname, be.bstrerror());
3538 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3539 target_attrname, jcr->last_fname, be.bstrerror());
3545 * Restore the actual data.
3547 if (st.st_size > 0) {
3548 used_bytes = (data - content);
3549 cnt = content_length - used_bytes;
3552 * Do a sanity check, the st.st_size should be the same as the number of bytes
3553 * we have available as data of the stream.
3555 if (cnt != st.st_size) {
3557 _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3558 target_attrname, jcr->last_fname);
3559 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3560 target_attrname, jcr->last_fname);
3565 cnt = write(attrfd, data, cnt);
3570 _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3571 target_attrname, jcr->last_fname, be.bstrerror());
3572 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3573 target_attrname, jcr->last_fname, be.bstrerror());
3579 cnt = content_length - used_bytes;
3585 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3589 if (symlink(linked_target, target_attrname) < 0) {
3593 _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3594 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3595 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3596 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3601 * Successfully restored xattr.
3603 retval = bxattr_exit_ok;
3610 * Restore owner and acl for non extensible attributes.
3612 if (!is_extensible) {
3613 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3619 * Gentile way of the system saying this type of xattr layering is not supported.
3620 * But as this is not an error we return a positive return value.
3622 retval = bxattr_exit_ok;
3625 retval = bxattr_exit_ok;
3629 _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3630 target_attrname, jcr->last_fname, be.bstrerror());
3631 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3632 target_attrname, jcr->last_fname, be.bstrerror());
3639 if (acl_text && *acl_text)
3640 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3642 #endif /* HAVE_ACL */
3645 * For a non extensible attribute restore access and modification time on the xattr.
3647 if (!is_extensible) {
3648 times[0].tv_sec = st.st_atime;
3649 times[0].tv_usec = 0;
3650 times[1].tv_sec = st.st_mtime;
3651 times[1].tv_usec = 0;
3653 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3657 _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3658 target_attrname, jcr->last_fname, be.bstrerror());
3659 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3660 target_attrname, jcr->last_fname, be.bstrerror());
3666 * Successfully restored xattr.
3668 retval = bxattr_exit_ok;
3673 _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3675 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3682 if (attrdirfd != -1) {
3691 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3694 bxattr_exit_code retval = bxattr_exit_ok;
3697 * First see if extended attributes or extensible attributes are present.
3698 * If not just pretend things went ok.
3700 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3701 jcr->xattr_data->u.build->nr_saved = 0;
3704 * As we change the cwd in the save function save the current cwd
3705 * for restore after return from the solaris_save_xattrs function.
3707 getcwd(cwd, sizeof(cwd));
3708 retval = solaris_save_xattrs(jcr, NULL, NULL);
3710 if (jcr->xattr_data->u.build->link_cache) {
3711 drop_xattr_link_cache(jcr);
3717 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr,
3720 uint32_t content_length)
3723 bool is_extensible = false;
3724 bxattr_exit_code retval = bxattr_exit_error;
3727 * First make sure we can restore xattr on the filesystem.
3730 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3731 case STREAM_XATTR_SOLARIS_SYS:
3732 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3734 _("Failed to restore extensible attributes on file \"%s\"\n"),
3736 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3741 is_extensible = true;
3744 case STREAM_XATTR_SOLARIS:
3745 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3747 _("Failed to restore extended attributes on file \"%s\"\n"),
3749 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3759 * As we change the cwd in the restore function save the current cwd
3760 * for restore after return from the solaris_restore_xattrs function.
3762 getcwd(cwd, sizeof(cwd));
3763 retval = solaris_restore_xattrs(jcr, is_extensible, content, content_length);
3772 * Function pointers to the build and parse function to use for these xattrs.
3774 static bxattr_exit_code (*os_build_xattr_streams)
3775 (JCR *jcr, FF_PKT *ff_pkt) =
3776 solaris_build_xattr_streams;
3777 static bxattr_exit_code (*os_parse_xattr_streams)
3778 (JCR *jcr, int stream, char *content, uint32_t content_length) =
3779 solaris_parse_xattr_streams;
3781 #endif /* defined(HAVE_SUN_OS) */
3784 * Entry points when compiled with support for XATTRs on a supported platform.
3786 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3789 * See if we are changing from one device to an other.
3790 * We save the current device we are scanning and compare
3791 * it with the current st_dev in the last stat performed on
3792 * the file we are currently storing.
3794 if (jcr->xattr_data->current_dev != ff_pkt->statp.st_dev) {
3796 * Reset the acl save flags.
3798 jcr->xattr_data->flags = 0;
3799 jcr->xattr_data->flags |= BXATTR_FLAG_SAVE_NATIVE;
3802 * Save that we started scanning a new filesystem.
3804 jcr->xattr_data->current_dev = ff_pkt->statp.st_dev;
3807 if ((jcr->xattr_data->flags & BXATTR_FLAG_SAVE_NATIVE) && os_parse_xattr_streams) {
3808 return os_build_xattr_streams(jcr, ff_pkt);
3810 return bxattr_exit_ok;
3814 bxattr_exit_code parse_xattr_streams(JCR *jcr,
3817 uint32_t content_length)
3822 bxattr_exit_code retval = bxattr_exit_error;
3825 * See if we are changing from one device to an other.
3826 * We save the current device we are restoring to and compare
3827 * it with the current st_dev in the last stat performed on
3828 * the file we are currently restoring.
3830 ret = lstat(jcr->last_fname, &st);
3837 retval = bxattr_exit_ok;
3841 _("Unable to stat file \"%s\": ERR=%s\n"),
3842 jcr->last_fname, be.bstrerror());
3843 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
3844 jcr->last_fname, be.bstrerror());
3852 if (jcr->xattr_data->current_dev != st.st_dev) {
3854 * Reset the acl save flags.
3856 jcr->xattr_data->flags = 0;
3857 jcr->xattr_data->flags |= BXATTR_FLAG_RESTORE_NATIVE;
3860 * Save that we started restoring to a new filesystem.
3862 jcr->xattr_data->current_dev = st.st_dev;
3866 * See if we are still restoring native xattr to this filesystem.
3868 if ((jcr->xattr_data->flags & BXATTR_FLAG_RESTORE_NATIVE) && os_parse_xattr_streams) {
3870 * See if we can parse this stream, and ifso give it a try.
3872 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3873 if (os_default_xattr_streams[cnt] == stream) {
3874 retval = os_parse_xattr_streams(jcr, stream, content, content_length);
3880 * Increment error count but don't log an error again for the same filesystem.
3882 jcr->xattr_data->u.parse->nr_errors++;
3883 retval = bxattr_exit_ok;
3888 * Issue a warning and discard the message. But pretend the restore was ok.
3890 Jmsg2(jcr, M_WARNING, 0,
3891 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3892 jcr->last_fname, stream);