2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 Bacula® is a registered trademark of Kern Sibbald.
17 * Functions to handle Extended Attributes for bacula.
19 * Extended Attributes are so OS specific we only restore Extended Attributes if
20 * they were saved using a filed on the same platform.
22 * Currently we support the following OSes:
23 * - AIX (Extended Attributes)
24 * - Darwin (Extended Attributes)
25 * - FreeBSD (Extended Attributes)
26 * - GNU HURD (Extended Attributes)
27 * - IRIX (Extended Attributes)
28 * - Linux (Extended Attributes)
29 * - NetBSD (Extended Attributes)
30 * - OpenBSD (Extended Attributes)
31 * (As it seems either they never implemented xattr or they are removed
32 * the support as it stated it was in version 3.1 but the current syscall
33 * tabled shows the extattr_ functions are not implemented. So as such we
34 * might eventually support xattr on OpenBSD when they implemented them using
35 * the same interface as FreeBSD and NetBSD.
36 * - Solaris (Extended Attributes and Extensible Attributes)
37 * - Tru64 (Extended Attributes)
39 * Written by Marco van Wieringen, November 2008
40 * Major overhaul January 2012 + June 2012
46 #if !defined(HAVE_XATTR)
48 * Entry points when compiled without support for XATTRs or on an unsupported platform.
50 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
52 return bxattr_exit_fatal;
55 bxattr_exit_code parse_xattr_streams(JCR *jcr,
58 uint32_t content_length)
60 return bxattr_exit_fatal;
64 * Send a XATTR stream to the SD.
66 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
68 BSOCK *sd = jcr->store_bsock;
70 #ifdef FD_NO_SEND_TEST
71 return bxattr_exit_ok;
77 if (jcr->xattr_data->u.build->content_length <= 0) {
78 return bxattr_exit_ok;
84 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
85 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
87 return bxattr_exit_fatal;
91 * Send the buffer to the storage deamon
93 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->u.build->content);
95 sd->msg = jcr->xattr_data->u.build->content;
96 sd->msglen = jcr->xattr_data->u.build->content_length;
100 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
102 return bxattr_exit_fatal;
105 jcr->JobBytes += sd->msglen;
107 if (!sd->signal(BNET_EOD)) {
108 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
110 return bxattr_exit_fatal;
112 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
113 return bxattr_exit_ok;
117 * First some generic functions for OSes that use the same xattr encoding scheme.
118 * Currently for all OSes except for Solaris.
120 #if !defined(HAVE_SUN_OS)
121 static void xattr_drop_internal_table(alist *xattr_value_list)
123 xattr_t *current_xattr;
126 * Walk the list of xattrs and free allocated memory on traversing.
128 foreach_alist(current_xattr, xattr_value_list) {
130 * See if we can shortcut.
132 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
135 free(current_xattr->name);
137 if (current_xattr->value_length > 0)
138 free(current_xattr->value);
143 delete xattr_value_list;
147 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
148 * which encodes one or more xattr_t structures.
150 * The Serialized stream consists of the following elements:
151 * magic - A magic string which makes it easy to detect any binary incompatabilites
152 * name_length - The length of the following xattr name
153 * name - The name of the extended attribute
154 * value_length - The length of the following xattr data
155 * value - The actual content of the extended attribute
157 * This is repeated 1 or more times.
160 static uint32_t serialize_xattr_stream(JCR *jcr,
161 uint32_t expected_serialize_len,
162 alist *xattr_value_list)
164 xattr_t *current_xattr;
168 * Make sure the serialized stream fits in the poolmem buffer.
169 * We allocate some more to be sure the stream is gonna fit.
171 jcr->xattr_data->u.build->content =
172 check_pool_memory_size(jcr->xattr_data->u.build->content,
173 expected_serialize_len + 10);
174 ser_begin(jcr->xattr_data->u.build->content,
175 expected_serialize_len + 10);
178 * Walk the list of xattrs and serialize the data.
180 foreach_alist(current_xattr, xattr_value_list) {
182 * See if we can shortcut.
184 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
187 ser_uint32(current_xattr->magic);
188 ser_uint32(current_xattr->name_length);
189 ser_bytes(current_xattr->name, current_xattr->name_length);
191 ser_uint32(current_xattr->value_length);
192 if (current_xattr->value_length > 0 && current_xattr->value) {
193 ser_bytes(current_xattr->value, current_xattr->value_length);
195 Dmsg3(100, "Backup xattr named %s, value %*s\n",
196 current_xattr->name, current_xattr->value, current_xattr->value);
198 Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
202 ser_end(jcr->xattr_data->u.build->content, expected_serialize_len + 10);
203 jcr->xattr_data->u.build->content_length =
204 ser_length(jcr->xattr_data->u.build->content);
206 return jcr->xattr_data->u.build->content_length;
209 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr,
211 uint32_t content_length,
212 alist *xattr_value_list)
215 xattr_t *current_xattr;
218 * Parse the stream and call restore_xattr_on_file for each extended attribute.
220 * Start unserializing the data. We keep on looping while we have not
221 * unserialized all bytes in the stream.
223 unser_begin(content, content_length);
224 while (unser_length(content) < content_length) {
226 * First make sure the magic is present. This way we can easily catch corruption.
227 * Any missing MAGIC is fatal we do NOT try to continue.
229 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
230 unser_uint32(current_xattr->magic);
231 if (current_xattr->magic != XATTR_MAGIC) {
233 _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
235 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
238 return bxattr_exit_error;
242 * Decode the valuepair. First decode the length of the name.
244 unser_uint32(current_xattr->name_length);
245 if (current_xattr->name_length == 0) {
247 _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
249 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
252 return bxattr_exit_error;
256 * Allocate room for the name and decode its content.
258 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
259 unser_bytes(current_xattr->name, current_xattr->name_length);
262 * The xattr_name needs to be null terminated.
264 current_xattr->name[current_xattr->name_length] = '\0';
267 * Decode the value length.
269 unser_uint32(current_xattr->value_length);
271 if (current_xattr->value_length > 0) {
273 * Allocate room for the value and decode its content.
275 current_xattr->value = (char *)malloc(current_xattr->value_length);
276 unser_bytes(current_xattr->value, current_xattr->value_length);
278 Dmsg3(100, "Restoring xattr named %s, value %*s\n",
279 current_xattr->name, current_xattr->value, current_xattr->value);
281 current_xattr->value = NULL;
282 Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
285 xattr_value_list->append(current_xattr);
288 unser_end(content, content_length);
289 return bxattr_exit_ok;
294 * This is a supported OS, See what kind of interface we should use.
296 #if defined(HAVE_AIX_OS)
298 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
299 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
300 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
301 #error "Missing full support for the Extended Attributes (EA) functions."
307 #error "Missing sys/ea.h header file"
311 * Define the supported XATTR streams for this OS
313 static int os_default_xattr_streams[1] = {
318 * Fallback to the non l-functions when those are not available.
320 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
323 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
326 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
327 #define llistea listea
330 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
334 char *xattr_list = NULL;
335 int cnt, xattr_count = 0;
336 uint32_t name_length;
337 int32_t xattr_list_len,
339 uint32_t expected_serialize_len = 0;
340 xattr_t *current_xattr;
341 alist *xattr_value_list = NULL;
342 bxattr_exit_code retval = bxattr_exit_error;
345 * First get the length of the available list with extended attributes.
347 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
348 switch (xattr_list_len) {
355 retval = bxattr_exit_ok;
359 * If the filesystem reports it doesn't support XATTRs we clear the
360 * BXATTR_FLAG_SAVE_NATIVE flag so we skip XATTR saves on all other files
361 * on the same filesystem. The BXATTR_FLAG_SAVE_NATIVE flags gets sets again
362 * when we change from one filesystem to an other.
364 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
365 retval = bxattr_exit_ok;
369 _("llistea error on file \"%s\": ERR=%s\n"),
370 jcr->last_fname, be.bstrerror());
371 Dmsg2(100, "llistea error file=%s ERR=%s\n",
372 jcr->last_fname, be.bstrerror());
378 retval = bxattr_exit_ok;
385 * Allocate room for the extented attribute list.
387 xattr_list = (char *)malloc(xattr_list_len + 1);
388 memset(xattr_list, 0, xattr_list_len + 1);
391 * Get the actual list of extended attributes names for a file.
393 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
394 switch (xattr_list_len) {
401 retval = bxattr_exit_ok;
405 _("llistea error on file \"%s\": ERR=%s\n"),
406 jcr->last_fname, be.bstrerror());
407 Dmsg2(100, "llistea error file=%s ERR=%s\n",
408 jcr->last_fname, be.bstrerror());
416 xattr_list[xattr_list_len] = '\0';
419 * Walk the list of extended attributes names and retrieve the data.
420 * We already count the bytes needed for serializing the stream later on.
422 for (bp = xattr_list;
423 (bp - xattr_list) + 1 < xattr_list_len;
424 bp = strchr(bp, '\0') + 1) {
428 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
434 name_length = strlen(bp);
435 if (skip_xattr || name_length == 0) {
436 Dmsg1(100, "Skipping xattr named %s\n", bp);
441 * First see how long the value is for the extended attribute.
443 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
444 switch (xattr_value_len) {
451 retval = bxattr_exit_ok;
455 _("lgetea error on file \"%s\": ERR=%s\n"),
456 jcr->last_fname, be.bstrerror());
457 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
458 jcr->last_fname, be.bstrerror());
468 * Each xattr valuepair starts with a magic so we can parse it easier.
470 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
471 memset(current_xattr, 0, sizeof(xattr_t));
472 current_xattr->magic = XATTR_MAGIC;
473 expected_serialize_len += sizeof(current_xattr->magic);
476 * Allocate space for storing the name.
478 current_xattr->name_length = name_length;
479 current_xattr->name = (char *)malloc(current_xattr->name_length);
480 memcpy(current_xattr->name, bp, current_xattr->name_length);
482 expected_serialize_len += sizeof(current_xattr->name_length) +
483 current_xattr->name_length;
485 switch (xattr_value_len) {
487 current_xattr->value = NULL;
488 current_xattr->value_length = 0;
489 expected_serialize_len += sizeof(current_xattr->value_length);
493 * Allocate space for storing the value.
495 current_xattr->value = (char *)malloc(xattr_value_len);
496 memset(current_xattr->value, 0, xattr_value_len);
498 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
499 if (xattr_value_len < 0) {
505 retval = bxattr_exit_ok;
509 _("lgetea error on file \"%s\": ERR=%s\n"),
510 jcr->last_fname, be.bstrerror());
511 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
512 jcr->last_fname, be.bstrerror());
517 * Default failure path out when retrieval of attr fails.
519 free(current_xattr->value);
520 free(current_xattr->name);
525 * Store the actual length of the value.
527 current_xattr->value_length = xattr_value_len;
528 expected_serialize_len += sizeof(current_xattr->value_length) +
529 current_xattr->value_length;
533 if (xattr_value_list == NULL) {
534 xattr_value_list = New(alist(10, not_owned_by_alist));
537 xattr_value_list->append(current_xattr);
541 * Protect ourself against things getting out of hand.
543 if (expected_serialize_len >= MAX_XATTR_STREAM) {
545 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
546 jcr->last_fname, MAX_XATTR_STREAM);
552 xattr_list = (char *)NULL;
555 * If we found any xattr send them to the SD.
557 if (xattr_count > 0) {
559 * Serialize the datastream.
561 if (serialize_xattr_stream(jcr,
562 expected_serialize_len,
563 xattr_value_list) < expected_serialize_len) {
565 _("Failed to serialize extended attributes on file \"%s\"\n"),
567 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
573 * Send the datastream to the SD.
575 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
577 retval = bxattr_exit_ok;
581 if (xattr_list != NULL) {
584 if (xattr_value_list != NULL) {
585 xattr_drop_internal_table(xattr_value_list);
591 static bxattr_exit_code aix_parse_xattr_streams(JCR *jcr,
594 uint32_t content_length)
596 xattr_t *current_xattr;
597 alist *xattr_value_list;
598 bxattr_exit_code retval = bxattr_exit_error;
600 xattr_value_list = New(alist(10, not_owned_by_alist));
602 if (unserialize_xattr_stream(jcr,
605 xattr_value_list) != bxattr_exit_ok) {
609 foreach_alist(current_xattr, xattr_value_list) {
610 if (lsetea(jcr->last_fname,
612 current_xattr->value,
613 current_xattr->value_length, 0) != 0) {
622 * If the filesystem reports it doesn't support XATTRs we clear
623 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
624 * on all other files on the same filesystem. The
625 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
626 * change from one filesystem to an other.
628 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
632 _("lsetea error on file \"%s\": ERR=%s\n"),
633 jcr->last_fname, be.bstrerror());
634 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
635 jcr->last_fname, be.bstrerror());
641 retval = bxattr_exit_ok;
644 xattr_drop_internal_table(xattr_value_list);
650 * Function pointers to the build and parse function to use for these xattrs.
652 static bxattr_exit_code (*os_build_xattr_streams)
653 (JCR *jcr, FF_PKT *ff_pkt) =
654 aix_xattr_build_streams;
655 static bxattr_exit_code (*os_parse_xattr_streams)
656 (JCR *jcr, int stream, char *content, uint32_t content_length) =
657 aix_parse_xattr_streams;
659 #elif defined(HAVE_IRIX_OS)
661 #include <sys/attributes.h>
664 * Define the supported XATTR streams for this OS
666 static int os_default_xattr_streams[1] = {
669 static const char *xattr_acl_skiplist[1] = {
672 static const char *xattr_skiplist[1] = {
676 struct xattr_naming_space {
681 static xattr_naming_space xattr_naming_spaces[] = {
687 ATTR_ROOT | ATTR_DONTFOLLOW
694 static bxattr_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
697 int cnt, length, xattr_count = 0;
698 attrlist_cursor_t cursor;
699 attrlist_t *attrlist;
700 attrlist_ent_t *attrlist_ent;
701 xattr_t *current_xattr;
702 alist *xattr_value_list = NULL;
703 uint32_t expected_serialize_len = 0;
704 bxattr_exit_code retval = bxattr_exit_error;
705 POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
707 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
708 memset(&cursor, 0, sizeof(attrlist_cursor_t));
710 if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
711 xattr_naming_spaces[cnt].flags, &cursor) != 0) {
716 retval = bxattr_exit_ok;
720 _("attr_list error on file \"%s\": ERR=%s\n"),
721 jcr->last_fname, be.bstrerror());
722 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
723 jcr->last_fname, be.bstrerror());
728 attrlist = (attrlist_t *)xattrbuf;
731 * Walk the available attributes.
733 for (cnt = 0; cnt < attrlist->al_count; cnt++) {
734 attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
737 * First determine if we can retrieve the xattr and how big it really is.
739 length = sizeof(dummy);
740 if (attr_get(jcr->last_fname, attrlist_ent->a_name, dummy,
741 &length, xattr_naming_spaces[cnt].flags) != 0) {
747 retval = bxattr_exit_ok;
751 * Size of the xattr is bigger then the 32 bytes dummy which is
752 * likely. As length now contains its actual length we can allocate
753 * a properly size buffer for the real retrieval.
758 _("attr_list error on file \"%s\": ERR=%s\n"),
759 jcr->last_fname, be.bstrerror());
760 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
761 jcr->last_fname, be.bstrerror());
767 * Each xattr valuepair starts with a magic so we can parse it easier.
769 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
770 memset(current_xattr, 0, sizeof(xattr_t));
771 current_xattr->magic = XATTR_MAGIC;
772 expected_serialize_len += sizeof(current_xattr->magic);
775 * Allocate space for storing the name.
776 * We store the name as <naming_space_name><xattr_name>
778 current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) +
779 strlen(attrlist_ent->a_name) + 1;
780 current_xattr->name = (char *)malloc(current_xattr->name_length);
781 bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
782 xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
784 expected_serialize_len += sizeof(current_xattr->name_length) +
785 current_xattr->name_length;
787 current_xattr->value_length = length;
788 current_xattr->value = (char *)malloc(current_xattr->value_length);
791 * Retrieve the actual value of the xattr.
793 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
794 &length, xattr_naming_spaces[cnt].flags) != 0) {
800 retval = bxattr_exit_ok;
804 * The buffer for the xattr isn't big enough. the value of
805 * current_xattr->value_length is updated with the actual size
806 * of the xattr. So we free the old buffer and create a new one
807 * and try again. Normally this cannot happen as we size the
808 * buffer using a call to attr_get before but in case of an
809 * race condition it might happen.
811 free(current_xattr->value);
812 current_xattr->value = (char *)malloc(length);
813 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
814 &length, xattr_naming_spaces[cnt].flags) != 0) {
818 retval = bxattr_exit_ok;
822 _("attr_list error on file \"%s\": ERR=%s\n"),
823 jcr->last_fname, be.bstrerror(errno));
824 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
825 jcr->last_fname, be.bstrerror());
834 _("attr_list error on file \"%s\": ERR=%s\n"),
835 jcr->last_fname, be.bstrerror());
836 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
837 jcr->last_fname, be.bstrerror());
842 * Default failure path out when retrieval of attr fails.
844 free(current_xattr->value);
845 free(current_xattr->name);
851 current_xattr->value_length = length;
852 expected_serialize_len += sizeof(current_xattr->value_length) +
853 current_xattr->value_length;
855 if (xattr_value_list == NULL) {
856 xattr_value_list = New(alist(10, not_owned_by_alist));
859 xattr_value_list->append(current_xattr);
863 * Protect ourself against things getting out of hand.
865 if (expected_serialize_len >= MAX_XATTR_STREAM) {
867 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
868 jcr->last_fname, MAX_XATTR_STREAM);
874 * See if there are more attributes available for a next run of attr_list.
876 if (attrlist->al_more == 0) {
883 * If we found any xattr send them to the SD.
885 if (xattr_count > 0) {
887 * Serialize the datastream.
889 if (serialize_xattr_stream(jcr,
890 expected_serialize_len,
891 xattr_value_list) < expected_serialize_len) {
893 _("Failed to serialize extended attributes on file \"%s\"\n"),
895 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
901 * Send the datastream to the SD.
903 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
905 retval = bxattr_exit_ok;
909 free_pool_memory(xattrbuf);
911 if (xattr_value_list != NULL) {
912 xattr_drop_internal_table(xattr_value_list);
918 static bxattr_exit_code irix_parse_xattr_streams(JCR *jcr,
921 uint32_t content_length)
924 int cnt, cmp_size, name_space_index, flags;
925 xattr_t *current_xattr;
926 alist *xattr_value_list;
927 bxattr_exit_code retval = bxattr_exit_error;
929 xattr_value_list = New(alist(10, not_owned_by_alist));
931 if (unserialize_xattr_stream(jcr,
934 xattr_value_list) != bxattr_exit_ok) {
938 foreach_alist(current_xattr, xattr_value_list) {
940 * See to what namingspace this xattr belongs to.
942 name_space_index = 0;
943 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
944 cmp_size = strlen(xattr_naming_spaces[cnt].name);
945 if (!strncasecmp(current_xattr->name,
946 xattr_naming_spaces[cnt].name,
948 name_space_index = cnt;
954 * If we got a xattr that doesn't belong to an valid namespace complain.
956 if (name_space_index == 0) {
958 _("Received illegal xattr named %s on file \"%s\"\n"),
959 current_xattr->name, jcr->last_fname);
960 Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
961 current_xattr->name, jcr->last_fname);
966 * Restore the xattr first try to create the attribute from scratch.
968 flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
969 bp = strchr(current_xattr->name, '.');
970 if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
971 current_xattr->value_length, flags) != 0) {
976 retval = bxattr_exit_ok;
980 * The xattr already exists we need to replace it.
982 flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
983 if (attr_set(jcr->last_fname, bp, current_xattr->value,
984 current_xattr->value_length, flags) != 0) {
987 retval = bxattr_exit_ok;
991 _("attr_set error on file \"%s\": ERR=%s\n"),
992 jcr->last_fname, be.bstrerror(errno));
993 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
994 jcr->last_fname, be.bstrerror());
1001 _("attr_set error on file \"%s\": ERR=%s\n"),
1002 jcr->last_fname, be.bstrerror());
1003 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
1004 jcr->last_fname, be.bstrerror());
1010 retval = bxattr_exit_ok;
1013 xattr_drop_internal_table(xattr_value_list);
1019 * Function pointers to the build and parse function to use for these xattrs.
1021 static bxattr_exit_code (*os_build_xattr_streams)
1022 (JCR *jcr, FF_PKT *ff_pkt) =
1023 irix_xattr_build_streams;
1024 static bxattr_exit_code (*os_parse_xattr_streams)
1025 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1026 irix_parse_xattr_streams;
1028 #elif defined(HAVE_DARWIN_OS) || \
1029 defined(HAVE_LINUX_OS) || \
1030 defined(HAVE_HURD_OS)
1032 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
1033 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
1034 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
1035 #error "Missing full support for the XATTR functions."
1038 #ifdef HAVE_SYS_XATTR_H
1039 #include <sys/xattr.h>
1041 #error "Missing sys/xattr.h header file"
1045 * Define the supported XATTR streams for this OS
1047 #if defined(HAVE_DARWIN_OS)
1048 static int os_default_xattr_streams[1] = {
1051 static const char *xattr_acl_skiplist[2] = {
1052 "com.apple.system.Security",
1055 static const char *xattr_skiplist[3] = {
1056 "com.apple.system.extendedsecurity",
1057 "com.apple.ResourceFork",
1060 #elif defined(HAVE_LINUX_OS)
1061 static int os_default_xattr_streams[1] = {
1064 static const char *xattr_acl_skiplist[3] = {
1065 "system.posix_acl_access",
1066 "system.posix_acl_default",
1069 static const char *xattr_skiplist[1] = {
1072 #elif defined(HAVE_HURD_OS)
1073 static int os_default_xattr_streams[1] = {
1076 static const char *xattr_acl_skiplist[1] = {
1079 static const char *xattr_skiplist[1] = {
1085 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
1086 * listxattr, getxattr and setxattr with an extra options argument
1087 * which mimics the l variants of the functions when we specify
1088 * XATTR_NOFOLLOW as the options value.
1090 #if defined(HAVE_DARWIN_OS)
1091 #define llistxattr(path, list, size) \
1092 listxattr((path), (list), (size), XATTR_NOFOLLOW)
1093 #define lgetxattr(path, name, value, size) \
1094 getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
1095 #define lsetxattr(path, name, value, size, flags) \
1096 setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
1099 * Fallback to the non l-functions when those are not available.
1101 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
1102 #define lgetxattr getxattr
1104 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
1105 #define lsetxattr setxattr
1107 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
1108 #define llistxattr listxattr
1112 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
1116 char *xattr_list = NULL;
1117 int cnt, xattr_count = 0;
1118 uint32_t name_length;
1119 int32_t xattr_list_len,
1121 uint32_t expected_serialize_len = 0;
1122 xattr_t *current_xattr;
1123 alist *xattr_value_list = NULL;
1124 bxattr_exit_code retval = bxattr_exit_error;
1127 * First get the length of the available list with extended attributes.
1129 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
1130 switch (xattr_list_len) {
1136 retval = bxattr_exit_ok;
1138 case BXATTR_ENOTSUP:
1140 * If the filesystem reports it doesn't support XATTRs we clear
1141 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1142 * on all other files on the same filesystem. The
1143 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1144 * change from one filesystem to an other.
1146 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1147 retval = bxattr_exit_ok;
1151 _("llistxattr error on file \"%s\": ERR=%s\n"),
1152 jcr->last_fname, be.bstrerror());
1153 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1154 jcr->last_fname, be.bstrerror());
1160 retval = bxattr_exit_ok;
1167 * Allocate room for the extented attribute list.
1169 xattr_list = (char *)malloc(xattr_list_len + 1);
1170 memset(xattr_list, 0, xattr_list_len + 1);
1173 * Get the actual list of extended attributes names for a file.
1175 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
1176 switch (xattr_list_len) {
1182 retval = bxattr_exit_ok;
1186 _("llistxattr error on file \"%s\": ERR=%s\n"),
1187 jcr->last_fname, be.bstrerror());
1188 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1189 jcr->last_fname, be.bstrerror());
1197 xattr_list[xattr_list_len] = '\0';
1200 * Walk the list of extended attributes names and retrieve the data.
1201 * We already count the bytes needed for serializing the stream later on.
1203 for (bp = xattr_list;
1204 (bp - xattr_list) + 1 < xattr_list_len;
1205 bp = strchr(bp, '\0') + 1) {
1209 * On some OSes you also get the acls in the extented attribute list.
1210 * So we check if we are already backing up acls and if we do we
1211 * don't store the extended attribute with the same info.
1213 if (ff_pkt->flags & FO_ACL) {
1214 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1215 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1223 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1226 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1227 if (bstrcmp(bp, xattr_skiplist[cnt])) {
1234 name_length = strlen(bp);
1235 if (skip_xattr || name_length == 0) {
1236 Dmsg1(100, "Skipping xattr named %s\n", bp);
1241 * First see how long the value is for the extended attribute.
1243 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1244 switch (xattr_value_len) {
1250 retval = bxattr_exit_ok;
1254 _("lgetxattr error on file \"%s\": ERR=%s\n"),
1255 jcr->last_fname, be.bstrerror());
1256 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1257 jcr->last_fname, be.bstrerror());
1267 * Each xattr valuepair starts with a magic so we can parse it easier.
1269 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1270 current_xattr->magic = XATTR_MAGIC;
1271 current_xattr->value = NULL;
1272 expected_serialize_len += sizeof(current_xattr->magic);
1275 * Allocate space for storing the name.
1277 current_xattr->name_length = name_length;
1278 current_xattr->name = (char *)malloc(current_xattr->name_length);
1279 memcpy(current_xattr->name, bp, current_xattr->name_length);
1281 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1283 switch (xattr_value_len) {
1285 current_xattr->value = NULL;
1286 current_xattr->value_length = 0;
1287 expected_serialize_len += sizeof(current_xattr->value_length);
1291 * Allocate space for storing the value.
1293 current_xattr->value = (char *)malloc(xattr_value_len);
1294 memset(current_xattr->value, 0, xattr_value_len);
1296 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1297 if (xattr_value_len < 0) {
1302 retval = bxattr_exit_ok;
1306 _("lgetxattr error on file \"%s\": ERR=%s\n"),
1307 jcr->last_fname, be.bstrerror());
1308 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1309 jcr->last_fname, be.bstrerror());
1314 * Default failure path out when retrieval of attr fails.
1316 free(current_xattr->value);
1317 free(current_xattr->name);
1318 free(current_xattr);
1323 * Store the actual length of the value.
1325 current_xattr->value_length = xattr_value_len;
1326 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1330 if (xattr_value_list == NULL) {
1331 xattr_value_list = New(alist(10, not_owned_by_alist));
1334 xattr_value_list->append(current_xattr);
1338 * Protect ourself against things getting out of hand.
1340 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1342 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1343 jcr->last_fname, MAX_XATTR_STREAM);
1349 xattr_list = (char *)NULL;
1352 * If we found any xattr send them to the SD.
1354 if (xattr_count > 0) {
1356 * Serialize the datastream.
1358 if (serialize_xattr_stream(jcr,
1359 expected_serialize_len,
1360 xattr_value_list) < expected_serialize_len) {
1362 _("Failed to serialize extended attributes on file \"%s\"\n"),
1364 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1370 * Send the datastream to the SD.
1372 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1374 retval = bxattr_exit_ok;
1378 if (xattr_list != NULL) {
1381 if (xattr_value_list != NULL) {
1382 xattr_drop_internal_table(xattr_value_list);
1388 static bxattr_exit_code generic_parse_xattr_streams(JCR *jcr,
1391 uint32_t content_length)
1393 xattr_t *current_xattr;
1394 alist *xattr_value_list;
1395 bxattr_exit_code retval = bxattr_exit_error;
1397 xattr_value_list = New(alist(10, not_owned_by_alist));
1399 if (unserialize_xattr_stream(jcr,
1402 xattr_value_list) != bxattr_exit_ok) {
1406 foreach_alist(current_xattr, xattr_value_list) {
1407 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1413 case BXATTR_ENOTSUP:
1415 * If the filesystem reports it doesn't support XATTRs we clear
1416 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1417 * on all other files on the same filesystem. The
1418 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1419 * change from one filesystem to an other.
1421 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
1425 _("lsetxattr error on file \"%s\": ERR=%s\n"),
1426 jcr->last_fname, be.bstrerror());
1427 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1428 jcr->last_fname, be.bstrerror());
1434 retval = bxattr_exit_ok;
1437 xattr_drop_internal_table(xattr_value_list);
1443 * Function pointers to the build and parse function to use for these xattrs.
1445 static bxattr_exit_code (*os_build_xattr_streams)
1446 (JCR *jcr, FF_PKT *ff_pkt) =
1447 generic_xattr_build_streams;
1448 static bxattr_exit_code (*os_parse_xattr_streams)
1449 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1450 generic_parse_xattr_streams;
1452 #elif defined(HAVE_FREEBSD_OS) || \
1453 defined(HAVE_NETBSD_OS) || \
1454 defined(HAVE_OPENBSD_OS)
1456 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1457 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1458 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1459 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1460 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1461 #error "Missing full support for the extattr functions."
1464 #ifdef HAVE_SYS_EXTATTR_H
1465 #include <sys/extattr.h>
1467 #error "Missing sys/extattr.h header file"
1470 #ifdef HAVE_LIBUTIL_H
1471 #include <libutil.h>
1474 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1475 #define extattr_get_link extattr_get_file
1477 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1478 #define extattr_set_link extattr_set_file
1480 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1481 #define extattr_list_link extattr_list_file
1484 #if defined(HAVE_FREEBSD_OS)
1485 static int os_default_xattr_streams[1] = {
1486 STREAM_XATTR_FREEBSD
1488 static int os_default_xattr_namespaces[2] = {
1489 EXTATTR_NAMESPACE_USER,
1490 EXTATTR_NAMESPACE_SYSTEM
1492 static const char *xattr_acl_skiplist[4] = {
1493 "system.posix1e.acl_access",
1494 "system.posix1e.acl_default",
1498 static const char *xattr_skiplist[1] = {
1501 #elif defined(HAVE_NETBSD_OS)
1502 static int os_default_xattr_streams[1] = {
1505 static int os_default_xattr_namespaces[2] = {
1506 EXTATTR_NAMESPACE_USER,
1507 EXTATTR_NAMESPACE_SYSTEM
1509 static const char *xattr_acl_skiplist[1] = {
1512 static const char *xattr_skiplist[1] = {
1515 #elif defined(HAVE_OPENBSD_OS)
1516 static int os_default_xattr_streams[1] = {
1517 STREAM_XATTR_OPENBSD
1519 static int os_default_xattr_namespaces[2] = {
1520 EXTATTR_NAMESPACE_USER,
1521 EXTATTR_NAMESPACE_SYSTEM
1523 static const char *xattr_acl_skiplist[1] = {
1526 static const char *xattr_skiplist[1] = {
1531 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1534 char *xattr_list = NULL;
1535 int cnt, index, xattr_count = 0;
1536 int32_t xattr_list_len,
1538 uint32_t expected_serialize_len = 0;
1539 unsigned int namespace_index;
1541 char *current_attrnamespace = NULL;
1542 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1543 xattr_t *current_xattr;
1544 alist *xattr_value_list = NULL;
1545 bxattr_exit_code retval = bxattr_exit_error;
1548 * Loop over all available xattr namespaces.
1550 for (namespace_index = 0;
1551 namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int);
1552 namespace_index++) {
1553 attrnamespace = os_default_xattr_namespaces[namespace_index];
1556 * First get the length of the available list with extended attributes.
1557 * If we get EPERM on system namespace, don't return error.
1558 * This is expected for normal users trying to archive the system
1559 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1560 * they've decided to return EOPNOTSUPP instead.
1562 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1563 switch (xattr_list_len) {
1569 retval = bxattr_exit_ok;
1571 #if defined(EOPNOTSUPP)
1575 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1583 _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1584 jcr->last_fname, be.bstrerror());
1585 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1586 jcr->last_fname, be.bstrerror());
1598 * Allocate room for the extented attribute list.
1600 xattr_list = (char *)malloc(xattr_list_len + 1);
1601 memset(xattr_list, 0, xattr_list_len + 1);
1604 * Get the actual list of extended attributes names for a file.
1606 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace,
1607 xattr_list, xattr_list_len);
1608 switch (xattr_list_len) {
1614 retval = bxattr_exit_ok;
1618 _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1619 jcr->last_fname, be.bstrerror());
1620 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1621 jcr->last_fname, be.bstrerror());
1629 xattr_list[xattr_list_len] = '\0';
1632 * Convert the numeric attrnamespace into a string representation and make
1633 * a private copy of that string. The extattr_namespace_to_string functions
1634 * returns a strdupped string which we need to free.
1636 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1638 _("Failed to convert %d into namespace on file \"%s\"\n"),
1639 attrnamespace, jcr->last_fname);
1640 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1641 attrnamespace, jcr->last_fname);
1646 * Walk the list of extended attributes names and retrieve the data.
1647 * We already count the bytes needed for serializing the stream later on.
1649 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1653 * Print the current name into the buffer as its not null terminated
1654 * we need to use the length encoded in the string for copying only
1657 cnt = xattr_list[index];
1658 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1659 cnt = ((int)sizeof(current_attrname) - 1);
1661 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1662 current_attrname[cnt] = '\0';
1665 * First make a xattr tuple of the current namespace and the name of
1666 * the xattr. e.g. something like user.<attrname> or system.<attrname>
1668 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s",
1669 current_attrnamespace, current_attrname);
1672 * On some OSes you also get the acls in the extented attribute list.
1673 * So we check if we are already backing up acls and if we do we
1674 * don't store the extended attribute with the same info.
1676 if (ff_pkt->flags & FO_ACL) {
1677 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1678 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1686 * On some OSes we want to skip certain xattrs which are in the
1687 * xattr_skiplist array.
1690 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1691 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1699 Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1704 * First see how long the value is for the extended attribute.
1706 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1707 current_attrname, NULL, 0);
1708 switch (xattr_value_len) {
1714 retval = bxattr_exit_ok;
1718 _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1719 jcr->last_fname, be.bstrerror());
1720 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1721 jcr->last_fname, be.bstrerror());
1731 * Each xattr valuepair starts with a magic so we can parse it easier.
1733 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1734 memset(current_xattr, 0, sizeof(xattr_t));
1735 current_xattr->magic = XATTR_MAGIC;
1736 expected_serialize_len += sizeof(current_xattr->magic);
1739 * Allocate space for storing the name.
1741 current_xattr->name_length = strlen(current_attrtuple);
1742 current_xattr->name = (char *)malloc(current_xattr->name_length);
1743 memcpy(current_xattr->name, current_attrtuple, current_xattr->name_length);
1745 expected_serialize_len += sizeof(current_xattr->name_length) +
1746 current_xattr->name_length;
1748 switch (xattr_value_len) {
1750 current_xattr->value = NULL;
1751 current_xattr->value_length = 0;
1752 expected_serialize_len += sizeof(current_xattr->value_length);
1756 * Allocate space for storing the value.
1758 current_xattr->value = (char *)malloc(xattr_value_len);
1759 memset(current_xattr->value, 0, xattr_value_len);
1761 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1762 current_attrname, current_xattr->value,
1764 if (xattr_value_len < 0) {
1769 retval = bxattr_exit_ok;
1773 _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1774 jcr->last_fname, be.bstrerror());
1775 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1776 jcr->last_fname, be.bstrerror());
1781 * Default failure path out when retrieval of attr fails.
1783 free(current_xattr->value);
1784 free(current_xattr->name);
1785 free(current_xattr);
1790 * Store the actual length of the value.
1792 current_xattr->value_length = xattr_value_len;
1793 expected_serialize_len += sizeof(current_xattr->value_length) +
1794 current_xattr->value_length;
1798 if (xattr_value_list == NULL) {
1799 xattr_value_list = New(alist(10, not_owned_by_alist));
1802 xattr_value_list->append(current_xattr);
1806 * Protect ourself against things getting out of hand.
1808 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1810 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1811 jcr->last_fname, MAX_XATTR_STREAM);
1817 * Drop the local copy of the current_attrnamespace.
1819 actuallyfree(current_attrnamespace);
1820 current_attrnamespace = NULL;
1823 * We are done with this xattr list.
1826 xattr_list = (char *)NULL;
1830 * If we found any xattr send them to the SD.
1832 if (xattr_count > 0) {
1834 * Serialize the datastream.
1836 if (serialize_xattr_stream(jcr,
1837 expected_serialize_len,
1838 xattr_value_list) < expected_serialize_len) {
1840 _("Failed to serialize extended attributes on file \"%s\"\n"),
1842 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1848 * Send the datastream to the SD.
1850 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1852 retval = bxattr_exit_ok;
1856 if (current_attrnamespace != NULL) {
1857 actuallyfree(current_attrnamespace);
1859 if (xattr_list != NULL) {
1862 if (xattr_value_list != NULL) {
1863 xattr_drop_internal_table(xattr_value_list);
1869 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr,
1872 uint32_t content_length)
1874 xattr_t *current_xattr;
1875 alist *xattr_value_list;
1876 int current_attrnamespace, cnt;
1877 char *attrnamespace, *attrname;
1878 bxattr_exit_code retval = bxattr_exit_error;
1880 xattr_value_list = New(alist(10, not_owned_by_alist));
1882 if (unserialize_xattr_stream(jcr,
1885 xattr_value_list) != bxattr_exit_ok) {
1889 foreach_alist(current_xattr, xattr_value_list) {
1891 * Try splitting the xattr_name into a namespace and name part.
1892 * The splitting character is a .
1894 attrnamespace = current_xattr->name;
1895 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1897 _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1898 current_xattr->name, jcr->last_fname);
1899 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1900 current_xattr->name, jcr->last_fname);
1906 * Make sure the attrnamespace makes sense.
1908 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1910 _("Failed to convert %s into namespace on file \"%s\"\n"),
1911 attrnamespace, jcr->last_fname);
1912 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1913 attrnamespace, jcr->last_fname);
1918 * Try restoring the extended attribute.
1920 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1921 attrname, current_xattr->value, current_xattr->value_length);
1922 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1931 _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1932 jcr->last_fname, be.bstrerror());
1933 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1934 jcr->last_fname, be.bstrerror());
1941 retval = bxattr_exit_ok;
1944 xattr_drop_internal_table(xattr_value_list);
1950 * Function pointers to the build and parse function to use for these xattrs.
1952 static bxattr_exit_code (*os_build_xattr_streams)
1953 (JCR *jcr, FF_PKT *ff_pkt) =
1954 bsd_build_xattr_streams;
1955 static bxattr_exit_code (*os_parse_xattr_streams)
1956 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1957 bsd_parse_xattr_streams;
1959 #elif defined(HAVE_OSF1_OS)
1961 #if !defined(HAVE_GETPROPLIST) || \
1962 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1963 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1964 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1965 !defined(HAVE_SETPROPLIST)
1966 #error "Missing full support for the Extended Attributes functions."
1969 #ifdef HAVE_SYS_PROPLIST_H
1970 #include <sys/proplist.h>
1972 #error "Missing sys/proplist.h header file"
1976 * Define the supported XATTR streams for this OS
1978 static int os_default_xattr_streams[1] = {
1981 static const char *xattr_acl_skiplist[1] = {
1984 static const char *xattr_skiplist[1] = {
1988 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1995 int xattr_count = 0;
1998 int32_t xattr_list_len,
2001 uint32_t expected_serialize_len = 0;
2002 xattr_t *current_xattr;
2003 alist *xattr_value_list = NULL;
2004 struct proplistname_args prop_args;
2005 bxattr_exit_code retval = bxattr_exit_error;
2006 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
2008 xattrbuf_size = sizeof_pool_memory(xattrbuf);
2009 xattrbuf_min_size = 0;
2010 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
2011 xattrbuf, &xattrbuf_min_size);
2014 * See what xattr are available.
2016 switch (xattr_list_len) {
2023 * If the filesystem reports it doesn't support XATTRs we clear
2024 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
2025 * on all other files on the same filesystem. The
2026 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
2027 * change from one filesystem to an other.
2029 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
2030 retval = bxattr_exit_ok;
2034 _("getproplist error on file \"%s\": ERR=%s\n"),
2035 jcr->last_fname, be.bstrerror());
2036 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
2037 jcr->last_fname, be.bstrerror());
2043 if (xattrbuf_min_size) {
2045 * The buffer isn't big enough to hold the xattr data, we now have
2046 * a minimum buffersize so we resize the buffer and try again.
2048 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
2049 xattrbuf_size = xattrbuf_min_size + 1;
2050 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
2051 xattrbuf, &xattrbuf_min_size);
2052 switch (xattr_list_len) {
2059 _("getproplist error on file \"%s\": ERR=%s\n"),
2060 jcr->last_fname, be.bstrerror());
2061 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
2062 jcr->last_fname, be.bstrerror());
2069 * This should never happen as we sized the buffer according to the minimumsize
2070 * returned by a previous getproplist call. If it does happen things are fishy and
2071 * we are better of forgetting this xattr as it seems its list is changing at this
2072 * exact moment so we can never make a good backup copy of it.
2074 retval = bxattr_exit_ok;
2083 retval = bxattr_exit_ok;
2092 * Walk the list of extended attributes names and retrieve the data.
2093 * We already count the bytes needed for serializing the stream later on.
2096 while (xattrbuf_size > 0) {
2098 * Call getproplist_entry to initialize name and value
2099 * pointers to entries position within buffer.
2101 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
2104 * On some OSes you also get the acls in the extented attribute list.
2105 * So we check if we are already backing up acls and if we do we
2106 * don't store the extended attribute with the same info.
2108 if (ff_pkt->flags & FO_ACL) {
2109 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
2110 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
2118 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
2121 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
2122 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
2130 Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
2135 * Each xattr valuepair starts with a magic so we can parse it easier.
2137 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
2138 memset(current_xattr, 0, sizeof(xattr_t));
2139 current_xattr->magic = XATTR_MAGIC;
2140 expected_serialize_len += sizeof(current_xattr->magic);
2142 current_xattr->name_length = strlen(xattr_name);
2143 current_xattr->name = bstrdup(xattr_name);
2145 expected_serialize_len += sizeof(current_xattr->name_length) +
2146 current_xattr->name_length;
2148 current_xattr->value_length = *xattr_value_len;
2149 current_xattr->value = (char *)malloc(current_xattr->value_length);
2150 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
2152 expected_serialize_len += sizeof(current_xattr->value_length) +
2153 current_xattr->value_length;
2155 if (xattr_value_list == NULL) {
2156 xattr_value_list = New(alist(10, not_owned_by_alist));
2159 xattr_value_list->append(current_xattr);
2163 * Protect ourself against things getting out of hand.
2165 if (expected_serialize_len >= MAX_XATTR_STREAM) {
2167 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2168 jcr->last_fname, MAX_XATTR_STREAM);
2174 * If we found any xattr send them to the SD.
2176 if (xattr_count > 0) {
2178 * Serialize the datastream.
2180 if (serialize_xattr_stream(jcr,
2181 expected_serialize_len,
2182 xattr_value_list) < expected_serialize_len) {
2184 _("Failed to serialize extended attributes on file \"%s\"\n"),
2186 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
2192 * Send the datastream to the SD.
2194 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
2196 retval = bxattr_exit_ok;
2200 if (xattr_value_list != NULL) {
2201 xattr_drop_internal_table(xattr_value_list);
2203 free_pool_memory(xattrbuf);
2208 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr,
2211 uint32_t content_length)
2213 char *bp, *xattrbuf = NULL;
2214 int32_t xattrbuf_size, cnt;
2215 xattr_t *current_xattr;
2216 alist *xattr_value_list;
2217 bxattr_exit_code retval = bxattr_exit_error;
2219 xattr_value_list = New(alist(10, not_owned_by_alist));
2221 if (unserialize_xattr_stream(jcr,
2224 xattr_value_list) != bxattr_exit_ok) {
2229 * See how big the propertylist must be.
2232 foreach_alist(current_xattr, xattr_value_list) {
2233 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
2236 xattrbuf = (char *)malloc(xattrbuf_size);
2239 * Add all value pairs to the proplist.
2243 foreach_alist(current_xattr, xattr_value_list) {
2244 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
2245 current_xattr->value, &bp);
2251 if (cnt != xattrbuf_size) {
2253 _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
2255 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
2261 * Restore the list of extended attributes on the file.
2263 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
2271 * If the filesystem reports it doesn't support XATTRs we clear
2272 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
2273 * on all other files on the same filesystem. The
2274 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
2275 * change from one filesystem to an other.
2277 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
2278 retval = bxattr_exit_ok;
2282 _("setproplist error on file \"%s\": ERR=%s\n"),
2283 jcr->last_fname, be.bstrerror());
2284 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
2285 jcr->last_fname, be.bstrerror());
2294 retval = bxattr_exit_ok;
2300 xattr_drop_internal_table(xattr_value_list);
2306 * Function pointers to the build and parse function to use for these xattrs.
2308 static bxattr_exit_code (*os_build_xattr_streams)
2309 (JCR *jcr, FF_PKT *ff_pkt) =
2310 tru64_build_xattr_streams;
2311 static bxattr_exit_code (*os_parse_xattr_streams)
2312 (JCR *jcr, int stream, char *content, uint32_t content_length) =
2313 tru64_parse_xattr_streams;
2315 #elif defined(HAVE_SUN_OS)
2317 * Solaris extended attributes were introduced in Solaris 9
2320 * Solaris extensible attributes were introduced in OpenSolaris
2321 * by PSARC 2007/315 Solaris extensible attributes are also
2322 * sometimes called extended system attributes.
2324 * man fsattr(5) on Solaris gives a wealth of info. The most
2325 * important bits are:
2327 * Attributes are logically supported as files within the file
2328 * system. The file system is therefore augmented with an
2329 * orthogonal name space of file attributes. Any file (includ-
2330 * ing attribute files) can have an arbitrarily deep attribute
2331 * tree associated with it. Attribute values are accessed by
2332 * file descriptors obtained through a special attribute inter-
2333 * face. This logical view of "attributes as files" allows the
2334 * leveraging of existing file system interface functionality
2335 * to support the construction, deletion, and manipulation of
2338 * The special files "." and ".." retain their accustomed
2339 * semantics within the attribute hierarchy. The "." attribute
2340 * file refers to the current directory and the ".." attribute
2341 * file refers to the parent directory. The unnamed directory
2342 * at the head of each attribute tree is considered the "child"
2343 * of the file it is associated with and the ".." file refers
2344 * to the associated file. For any non-directory file with
2345 * attributes, the ".." entry in the unnamed directory refers
2346 * to a file that is not a directory.
2348 * Conceptually, the attribute model is fully general. Extended
2349 * attributes can be any type of file (doors, links, direc-
2350 * tories, and so forth) and can even have their own attributes
2351 * (fully recursive). As a result, the attributes associated
2352 * with a file could be an arbitrarily deep directory hierarchy
2353 * where each attribute could have an equally complex attribute
2354 * tree associated with it. Not all implementations are able
2355 * to, or want to, support the full model. Implementation are
2356 * therefore permitted to reject operations that are not sup-
2357 * ported. For example, the implementation for the UFS file
2358 * system allows only regular files as attributes (for example,
2359 * no sub-directories) and rejects attempts to place attributes
2362 * The following list details the operations that are rejected
2363 * in the current implementation:
2365 * link Any attempt to create links between
2366 * attribute and non-attribute space
2367 * is rejected to prevent security-
2368 * related or otherwise sensitive
2369 * attributes from being exposed, and
2370 * therefore manipulable, as regular
2373 * rename Any attempt to rename between
2374 * attribute and non-attribute space
2375 * is rejected to prevent an already
2376 * linked file from being renamed and
2377 * thereby circumventing the link res-
2380 * mkdir, symlink, mknod Any attempt to create a "non-
2381 * regular" file in attribute space is
2382 * rejected to reduce the functional-
2383 * ity, and therefore exposure and
2384 * risk, of the initial implementa-
2387 * The entire available name space has been allocated to "gen-
2388 * eral use" to bring the implementation in line with the NFSv4
2389 * draft standard [NFSv4]. That standard defines "named attri-
2390 * butes" (equivalent to Solaris Extended Attributes) with no
2391 * naming restrictions. All Sun applications making use of
2392 * opaque extended attributes will use the prefix "SUNW".
2395 #ifdef HAVE_SYS_ATTR_H
2396 #include <sys/attr.h>
2403 #ifdef HAVE_SYS_NVPAIR_H
2404 #include <sys/nvpair.h>
2407 #ifdef HAVE_SYS_ACL_H
2408 #include <sys/acl.h>
2411 #if !defined(HAVE_OPENAT) || \
2412 !defined(HAVE_UNLINKAT) || \
2413 !defined(HAVE_FCHOWNAT) || \
2414 !defined(HAVE_FUTIMESAT)
2415 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2419 * Define the supported XATTR streams for this OS
2421 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2422 static int os_default_xattr_streams[2] = {
2423 STREAM_XATTR_SOLARIS,
2424 STREAM_XATTR_SOLARIS_SYS
2427 static int os_default_xattr_streams[1] = {
2428 STREAM_XATTR_SOLARIS
2430 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2433 * This code creates a temporary cache with entries for each xattr which has
2434 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2436 static inline xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2438 xattr_link_cache_entry_t *ptr;
2440 foreach_alist(ptr, jcr->xattr_data->u.build->link_cache) {
2441 if (ptr && ptr->inum == inum) {
2448 static inline void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2450 xattr_link_cache_entry_t *ptr;
2452 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2453 memset(ptr, 0, sizeof(xattr_link_cache_entry_t));
2455 ptr->target = bstrdup(target);
2457 if (!jcr->xattr_data->u.build->link_cache) {
2458 jcr->xattr_data->u.build->link_cache = New(alist(10, not_owned_by_alist));
2460 jcr->xattr_data->u.build->link_cache->append(ptr);
2463 static inline void drop_xattr_link_cache(JCR *jcr)
2465 xattr_link_cache_entry_t *ptr;
2468 * Walk the list of xattr link cache entries and free allocated memory on traversing.
2470 foreach_alist(ptr, jcr->xattr_data->u.build->link_cache) {
2475 delete jcr->xattr_data->u.build->link_cache;
2476 jcr->xattr_data->u.build->link_cache = NULL;
2479 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2481 * This function returns true if a non default extended system attribute
2482 * list is associated with fd and returns false when an error has occured
2483 * or when only extended system attributes other than archive,
2484 * av_modified or crtime are set.
2486 * The function returns true for the following cases:
2488 * - any extended system attribute other than the default attributes
2489 * ('archive', 'av_modified' and 'crtime') is set
2490 * - nvlist has NULL name string
2491 * - nvpair has data type of 'nvlist'
2492 * - default data type.
2494 static bool solaris_has_non_transient_extensible_attributes(int fd)
2502 bool retval = false;
2504 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2509 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2510 name = nvpair_name(pair);
2513 fattr = name_to_attr(name);
2519 type = nvpair_type(pair);
2521 case DATA_TYPE_BOOLEAN_VALUE:
2522 if (nvpair_value_boolean_value(pair, &value) != 0) {
2525 if (value && fattr != F_ARCHIVE &&
2526 fattr != F_AV_MODIFIED) {
2531 case DATA_TYPE_UINT64_ARRAY:
2532 if (fattr != F_CRTIME) {
2537 case DATA_TYPE_NVLIST:
2545 if (response != NULL) {
2546 nvlist_free(response);
2550 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2552 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2554 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2555 * There is no need to store those acls as we already store the stat bits too.
2557 static bool acl_is_trivial(int count, aclent_t *entries)
2562 for (n = 0; n < count; n++) {
2564 if (!(ace->a_type == USER_OBJ ||
2565 ace->a_type == GROUP_OBJ ||
2566 ace->a_type == OTHER_OBJ ||
2567 ace->a_type == CLASS_OBJ))
2572 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2574 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2576 bxattr_exit_code retval = bxattr_exit_error;
2578 #ifdef HAVE_EXTENDED_ACL
2583 * See if this attribute has an ACL
2585 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2586 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2588 * See if there is a non trivial acl on the file.
2590 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2591 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2596 retval = bxattr_exit_ok;
2600 _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2601 attrname, jcr->last_fname, be.bstrerror());
2602 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2603 attrname, jcr->last_fname, be.bstrerror());
2609 #if defined(ACL_SID_FMT)
2611 * New format flag added in newer Solaris versions.
2613 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2615 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2616 #endif /* ACL_SID_FMT */
2618 *acl_text = acl_totext(aclp, flags);
2626 retval = bxattr_exit_ok;
2627 #else /* HAVE_EXTENDED_ACL */
2629 aclent_t *acls = NULL;
2632 * See if this attribute has an ACL
2635 n = facl(fd, GETACLCNT, 0, NULL);
2637 n = acl(attrname, GETACLCNT, 0, NULL);
2640 if (n >= MIN_ACL_ENTRIES) {
2641 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2642 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2643 acl(attrname, GETACL, n, acls) != n) {
2649 retval = bxattr_exit_ok;
2653 _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2654 attrname, jcr->last_fname, be.bstrerror());
2655 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2656 attrname, jcr->last_fname, be.bstrerror());
2663 * See if there is a non trivial acl on the file.
2665 if (!acl_is_trivial(n, acls)) {
2666 if ((*acl_text = acltotext(acls, n)) == NULL) {
2670 _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2671 attrname, jcr->last_fname, be.bstrerror());
2672 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2673 attrname, jcr->last_fname, be.bstrerror());
2685 retval = bxattr_exit_ok;
2686 #endif /* HAVE_EXTENDED_ACL */
2688 #else /* HAVE_ACL */
2689 retval = bxattr_exit_ok;
2690 #endif /* HAVE_ACL */
2697 * Forward declaration for recursive function call.
2699 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2702 * Save an extended or extensible attribute.
2703 * This is stored as an opaque stream of bytes with the following encoding:
2705 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2707 * or for a hardlinked or symlinked attribute
2709 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2711 * xattr_name can be a subpath relative to the file the xattr is on.
2712 * stat_buffer is the string representation of the stat struct.
2713 * acl_string is an acl text when a non trivial acl is set on the xattr.
2714 * actual_xattr_data is the content of the xattr file.
2716 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2717 const char *attrname, bool toplevel_hidden_dir, int stream)
2722 xattr_link_cache_entry_t *xlce;
2723 char target_attrname[PATH_MAX];
2724 char link_source[PATH_MAX];
2725 char *acl_text = NULL;
2726 char attribs[MAXSTRING];
2727 char buffer[XATTR_BUFSIZ];
2728 bxattr_exit_code retval = bxattr_exit_error;
2730 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2733 * Get the stats of the extended or extensible attribute.
2735 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2740 retval = bxattr_exit_ok;
2744 _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2745 target_attrname, jcr->last_fname, be.bstrerror());
2746 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2747 target_attrname, jcr->last_fname, be.bstrerror());
2753 * Based on the filetype perform the correct action. We support most filetypes here, more
2754 * then the actual implementation on Solaris supports so some code may never get executed
2755 * due to limitations in the implementation.
2757 switch (st.st_mode & S_IFMT) {
2762 * Get any acl on the xattr.
2764 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2768 * The current implementation of xattr on Solaris doesn't support this,
2769 * but if it ever does we are prepared.
2770 * Encode the stat struct into an ASCII representation.
2772 encode_stat(attribs, &st, sizeof(st), 0, stream);
2773 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2774 target_attrname, 0, attribs, 0,
2775 (acl_text) ? acl_text : "", 0);
2779 * Get any acl on the xattr.
2781 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2785 * See if this is the toplevel_hidden_dir being saved.
2787 if (toplevel_hidden_dir) {
2789 * Save the data for later storage when we encounter a real xattr.
2790 * We store the data in the jcr->xattr_data->u.build->content buffer
2791 * and flush that just before sending out the first real xattr.
2792 * Encode the stat struct into an ASCII representation and jump
2793 * out of the function.
2795 encode_stat(attribs, &st, sizeof(st), 0, stream);
2796 cnt = bsnprintf(buffer, sizeof(buffer),
2798 target_attrname, 0, attribs, 0,
2799 (acl_text) ? acl_text : "", 0);
2800 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2801 jcr->xattr_data->u.build->content_length = cnt;
2805 * The current implementation of xattr on Solaris doesn't support this,
2806 * but if it ever does we are prepared.
2807 * Encode the stat struct into an ASCII representation.
2809 encode_stat(attribs, &st, sizeof(st), 0, stream);
2810 cnt = bsnprintf(buffer, sizeof(buffer),
2812 target_attrname, 0, attribs, 0,
2813 (acl_text) ? acl_text : "", 0);
2818 * If this is a hardlinked file check the inode cache for a hit.
2820 if (st.st_nlink > 1) {
2822 * See if the cache already knows this inode number.
2824 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2826 * Generate a xattr encoding with the reference to the target in there.
2828 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2829 cnt = bsnprintf(buffer, sizeof(buffer),
2831 target_attrname, 0, attribs, 0, xlce->target, 0);
2832 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2833 jcr->xattr_data->u.build->content_length = cnt;
2834 retval = send_xattr_stream(jcr, stream);
2837 * For a hard linked file we are ready now, no need to recursively
2838 * save the attributes.
2844 * Store this hard linked file in the cache.
2845 * Store the name relative to the top level xattr space.
2847 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2851 * Get any acl on the xattr.
2853 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2858 * Encode the stat struct into an ASCII representation.
2860 encode_stat(attribs, &st, sizeof(st), 0, stream);
2861 cnt = bsnprintf(buffer, sizeof(buffer),
2863 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2866 * Open the extended or extensible attribute file.
2868 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2873 retval = bxattr_exit_ok;
2877 _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2878 target_attrname, jcr->last_fname, be.bstrerror());
2879 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2880 target_attrname, jcr->last_fname, be.bstrerror());
2887 * The current implementation of xattr on Solaris doesn't support this, but if it
2888 * ever does we are prepared.
2889 * Encode the stat struct into an ASCII representation.
2891 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2896 retval = bxattr_exit_ok;
2900 _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2901 target_attrname, jcr->last_fname, be.bstrerror());
2902 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2903 target_attrname, jcr->last_fname, be.bstrerror());
2909 * Generate a xattr encoding with the reference to the target in there.
2911 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2912 cnt = bsnprintf(buffer, sizeof(buffer),
2914 target_attrname, 0, attribs, 0, link_source, 0);
2915 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2916 jcr->xattr_data->u.build->content_length = cnt;
2917 retval = send_xattr_stream(jcr, stream);
2919 if (retval == bxattr_exit_ok) {
2920 jcr->xattr_data->u.build->nr_saved++;
2924 * For a soft linked file we are ready now, no need to recursively save the attributes.
2932 * See if this is the first real xattr being saved.
2933 * If it is save the toplevel_hidden_dir attributes first.
2934 * This is easy as its stored already in the
2935 * jcr->xattr_data->u.build->content buffer.
2937 if (jcr->xattr_data->u.build->nr_saved == 0) {
2938 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2939 if (retval != bxattr_exit_ok) {
2942 jcr->xattr_data->u.build->nr_saved++;
2945 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2946 jcr->xattr_data->u.build->content_length = cnt;
2949 * Only dump the content of regular files.
2951 switch (st.st_mode & S_IFMT) {
2953 if (st.st_size > 0) {
2955 * Protect ourself against things getting out of hand.
2957 if (st.st_size >= MAX_XATTR_STREAM) {
2959 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2960 jcr->last_fname, MAX_XATTR_STREAM);
2964 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2965 jcr->xattr_data->u.build->content =
2966 check_pool_memory_size(jcr->xattr_data->u.build->content,
2967 jcr->xattr_data->u.build->content_length + cnt);
2968 memcpy(jcr->xattr_data->u.build->content +
2969 jcr->xattr_data->u.build->content_length, buffer, cnt);
2970 jcr->xattr_data->u.build->content_length += cnt;
2975 _("Unable to read content of xattr %s on file \"%s\"\n"),
2976 target_attrname, jcr->last_fname);
2977 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2978 target_attrname, jcr->last_fname);
2989 * We build a new xattr stream send it to the SD.
2991 retval = send_xattr_stream(jcr, stream);
2992 if (retval != bxattr_exit_ok) {
2995 jcr->xattr_data->u.build->nr_saved++;
2998 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2999 * available on this extended attribute.
3001 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
3004 * The recursive call could change our working dir so change back to the wanted workdir.
3006 if (fchdir(fd) < 0) {
3011 retval = bxattr_exit_ok;
3015 _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
3016 jcr->last_fname, be.bstrerror());
3017 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
3018 jcr->last_fname, fd, be.bstrerror());
3024 if (acl_text != NULL) {
3033 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
3036 int fd, filefd = -1, attrdirfd = -1;
3039 char current_xattr_namespace[PATH_MAX];
3040 bxattr_exit_code retval = bxattr_exit_error;
3043 * Determine what argument to use. Use attr_parent when set
3044 * (recursive call) or jcr->last_fname for first call. Also save
3045 * the current depth of the xattr_space we are in.
3049 if (xattr_namespace) {
3050 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
3051 xattr_namespace, attr_parent);
3053 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
3056 name = jcr->last_fname;
3057 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
3061 * Open the file on which to save the xattrs read-only.
3063 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
3068 retval = bxattr_exit_ok;
3072 _("Unable to open file \"%s\": ERR=%s\n"),
3073 jcr->last_fname, be.bstrerror());
3074 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
3075 jcr->last_fname, be.bstrerror());
3081 * Open the xattr naming space.
3083 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3089 * Gentile way of the system saying this type of xattr layering is not supported.
3090 * Which is not problem we just forget about this this xattr.
3091 * But as this is not an error we return a positive return value.
3093 retval = bxattr_exit_ok;
3096 retval = bxattr_exit_ok;
3100 _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
3101 name, jcr->last_fname, be.bstrerror());
3102 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
3103 name, jcr->last_fname, be.bstrerror());
3109 * We need to change into the attribute directory to determine if each of the
3110 * attributes should be saved.
3112 if (fchdir(attrdirfd) < 0) {
3116 _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3117 jcr->last_fname, be.bstrerror());
3118 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
3119 jcr->last_fname, attrdirfd, be.bstrerror());
3124 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
3125 * else because the readdir returns "." entry after the extensible attr entry.
3126 * And as we want this entry before anything else we better just save its data.
3129 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
3130 true, STREAM_XATTR_SOLARIS);
3132 if ((fd = dup(attrdirfd)) == -1 ||
3133 (dirp = fdopendir(fd)) == (DIR *)NULL) {
3137 _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
3138 jcr->last_fname, be.bstrerror());
3139 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
3140 jcr->last_fname, fd, be.bstrerror());
3146 * Walk the namespace.
3148 while ((dp = readdir(dirp)) != NULL) {
3150 * Skip only the toplevel . dir.
3152 if (!attr_parent && bstrcmp(dp->d_name, "."))
3156 * Skip all .. directories
3158 if (bstrcmp(dp->d_name, ".."))
3161 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
3162 current_xattr_namespace, dp->d_name, jcr->last_fname);
3164 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3166 * We are not interested in read-only extensible attributes.
3168 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
3169 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
3170 current_xattr_namespace, dp->d_name, jcr->last_fname);
3176 * We are only interested in read-write extensible attributes
3177 * when they contain non-transient values.
3179 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
3181 * Determine if there are non-transient system attributes at the toplevel.
3182 * We need to provide a fd to the open file.
3184 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
3185 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
3186 current_xattr_namespace, dp->d_name, jcr->last_fname);
3193 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3194 false, STREAM_XATTR_SOLARIS_SYS);
3197 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
3202 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3203 false, STREAM_XATTR_SOLARIS);
3207 retval = bxattr_exit_ok;
3210 if (attrdirfd != -1)
3218 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr,
3220 const char *attrname,
3223 #ifdef HAVE_EXTENDED_ACL
3227 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
3229 _("Unable to convert acl from text on file \"%s\"\n"),
3231 return bxattr_exit_error;
3234 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
3235 acl_set(attrname, aclp) != 0) {
3239 _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3240 attrname, jcr->last_fname, be.bstrerror());
3241 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3242 attrname, jcr->last_fname, be.bstrerror());
3243 return bxattr_exit_error;
3249 return bxattr_exit_ok;
3251 #else /* HAVE_EXTENDED_ACL */
3253 aclent_t *acls = NULL;
3255 acls = aclfromtext(acl_text, &n);
3257 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
3258 acl(attrname, SETACL, n, acls) != 0) {
3262 _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3263 attrname, jcr->last_fname, be.bstrerror());
3264 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3265 attrname, jcr->last_fname, be.bstrerror());
3266 return bxattr_exit_error;
3273 return bxattr_exit_ok;
3275 #endif /* HAVE_EXTENDED_ACL */
3278 #endif /* HAVE_ACL */
3280 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr,
3283 uint32_t content_length)
3286 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
3287 int used_bytes, cnt;
3288 char *bp, *target_attrname, *attribs;
3289 char *linked_target = NULL;
3290 char *acl_text = NULL;
3294 struct timeval times[2];
3295 bxattr_exit_code retval = bxattr_exit_error;
3298 * Parse the xattr stream. First the part that is the same for all xattrs.
3303 * The name of the target xattr has a leading / we are not interested
3304 * in that so skip it when decoding the string. We always start a the /
3305 * of the xattr space anyway.
3307 target_attrname = content + 1;
3308 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
3309 (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3315 * Open the file on which to restore the xattrs read-only.
3317 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
3321 _("Unable to open file \"%s\": ERR=%s\n"),
3322 jcr->last_fname, be.bstrerror());
3323 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
3324 jcr->last_fname, be.bstrerror());
3329 * Open the xattr naming space and make it the current working dir.
3331 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3335 _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
3336 jcr->last_fname, be.bstrerror());
3337 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
3338 jcr->last_fname, be.bstrerror());
3342 if (fchdir(attrdirfd) < 0) {
3346 _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3347 jcr->last_fname, be.bstrerror());
3348 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
3349 jcr->last_fname, attrdirfd, be.bstrerror());
3354 * Try to open the correct xattr subdir based on the target_attrname given.
3355 * e.g. check if its a subdir attrname. Each / in the string makes us go
3358 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
3361 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
3365 _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3366 target_attrname, jcr->last_fname, be.bstrerror());
3367 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3368 target_attrname, jcr->last_fname, be.bstrerror());
3376 * Open the xattr naming space.
3378 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3382 _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
3383 target_attrname, jcr->last_fname, be.bstrerror());
3384 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
3385 target_attrname, jcr->last_fname, be.bstrerror());
3393 * Make the xattr space our current workingdir.
3395 if (fchdir(attrdirfd) < 0) {
3399 _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
3400 target_attrname, jcr->last_fname, be.bstrerror());
3401 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
3402 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
3406 target_attrname = ++bp;
3410 * Decode the attributes from the stream.
3412 decode_stat(attribs, &st, sizeof(st), &inum);
3415 * Decode the next field (acl_text).
3417 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
3418 (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3424 * Based on the filetype perform the correct action. We support most filetypes here, more
3425 * then the actual implementation on Solaris supports so some code may never get executed
3426 * due to limitations in the implementation.
3428 switch (st.st_mode & S_IFMT) {
3431 * The current implementation of xattr on Solaris doesn't support this,
3432 * but if it ever does we are prepared.
3434 unlinkat(attrdirfd, target_attrname, 0);
3435 if (mkfifo(target_attrname, st.st_mode) < 0) {
3439 _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3440 target_attrname, jcr->last_fname, be.bstrerror());
3441 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
3442 target_attrname, jcr->last_fname, be.bstrerror());
3449 * The current implementation of xattr on Solaris doesn't support this,
3450 * but if it ever does we are prepared.
3452 unlinkat(attrdirfd, target_attrname, 0);
3453 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3457 _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3458 target_attrname, jcr->last_fname, be.bstrerror());
3459 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3460 target_attrname, jcr->last_fname, be.bstrerror());
3466 * If its not the hidden_dir create the entry.
3467 * The current implementation of xattr on Solaris doesn't support this,
3468 * but if it ever does we are prepared.
3470 if (!bstrcmp(target_attrname, ".")) {
3471 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3472 if (mkdir(target_attrname, st.st_mode) < 0) {
3475 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3476 target_attrname, jcr->last_fname, be.bstrerror());
3477 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3478 target_attrname, jcr->last_fname, be.bstrerror());
3485 * See if this is a hard linked file. e.g. inum != 0
3490 unlinkat(attrdirfd, target_attrname, 0);
3491 if (link(linked_target, target_attrname) < 0) {
3495 _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3496 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3497 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3498 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3503 * Successfully restored xattr.
3505 retval = bxattr_exit_ok;
3508 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3509 (used_bytes = (bp - content)) >= (int32_t)content_length) {
3513 if (used_bytes < (int32_t)(content_length - 1))
3517 * Restore the actual xattr.
3519 if (!is_extensible) {
3520 unlinkat(attrdirfd, target_attrname, 0);
3523 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3527 _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3528 target_attrname, jcr->last_fname, be.bstrerror());
3529 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3530 target_attrname, jcr->last_fname, be.bstrerror());
3536 * Restore the actual data.
3538 if (st.st_size > 0) {
3539 used_bytes = (data - content);
3540 cnt = content_length - used_bytes;
3543 * Do a sanity check, the st.st_size should be the same as the number of bytes
3544 * we have available as data of the stream.
3546 if (cnt != st.st_size) {
3548 _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3549 target_attrname, jcr->last_fname);
3550 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3551 target_attrname, jcr->last_fname);
3556 cnt = write(attrfd, data, cnt);
3561 _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3562 target_attrname, jcr->last_fname, be.bstrerror());
3563 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3564 target_attrname, jcr->last_fname, be.bstrerror());
3570 cnt = content_length - used_bytes;
3576 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3580 if (symlink(linked_target, target_attrname) < 0) {
3584 _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3585 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3586 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3587 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3592 * Successfully restored xattr.
3594 retval = bxattr_exit_ok;
3601 * Restore owner and acl for non extensible attributes.
3603 if (!is_extensible) {
3604 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3610 * Gentile way of the system saying this type of xattr layering is not supported.
3611 * But as this is not an error we return a positive return value.
3613 retval = bxattr_exit_ok;
3616 retval = bxattr_exit_ok;
3620 _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3621 target_attrname, jcr->last_fname, be.bstrerror());
3622 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3623 target_attrname, jcr->last_fname, be.bstrerror());
3630 if (acl_text && *acl_text)
3631 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3633 #endif /* HAVE_ACL */
3636 * For a non extensible attribute restore access and modification time on the xattr.
3638 if (!is_extensible) {
3639 times[0].tv_sec = st.st_atime;
3640 times[0].tv_usec = 0;
3641 times[1].tv_sec = st.st_mtime;
3642 times[1].tv_usec = 0;
3644 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3648 _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3649 target_attrname, jcr->last_fname, be.bstrerror());
3650 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3651 target_attrname, jcr->last_fname, be.bstrerror());
3657 * Successfully restored xattr.
3659 retval = bxattr_exit_ok;
3664 _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3666 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3673 if (attrdirfd != -1) {
3682 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3685 bxattr_exit_code retval = bxattr_exit_ok;
3688 * First see if extended attributes or extensible attributes are present.
3689 * If not just pretend things went ok.
3691 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3692 jcr->xattr_data->u.build->nr_saved = 0;
3695 * As we change the cwd in the save function save the current cwd
3696 * for restore after return from the solaris_save_xattrs function.
3698 getcwd(cwd, sizeof(cwd));
3699 retval = solaris_save_xattrs(jcr, NULL, NULL);
3701 if (jcr->xattr_data->u.build->link_cache) {
3702 drop_xattr_link_cache(jcr);
3708 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr,
3711 uint32_t content_length)
3714 bool is_extensible = false;
3715 bxattr_exit_code retval = bxattr_exit_error;
3718 * First make sure we can restore xattr on the filesystem.
3721 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3722 case STREAM_XATTR_SOLARIS_SYS:
3723 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3725 _("Failed to restore extensible attributes on file \"%s\"\n"),
3727 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3732 is_extensible = true;
3735 case STREAM_XATTR_SOLARIS:
3736 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3738 _("Failed to restore extended attributes on file \"%s\"\n"),
3740 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3750 * As we change the cwd in the restore function save the current cwd
3751 * for restore after return from the solaris_restore_xattrs function.
3753 getcwd(cwd, sizeof(cwd));
3754 retval = solaris_restore_xattrs(jcr, is_extensible, content, content_length);
3763 * Function pointers to the build and parse function to use for these xattrs.
3765 static bxattr_exit_code (*os_build_xattr_streams)
3766 (JCR *jcr, FF_PKT *ff_pkt) =
3767 solaris_build_xattr_streams;
3768 static bxattr_exit_code (*os_parse_xattr_streams)
3769 (JCR *jcr, int stream, char *content, uint32_t content_length) =
3770 solaris_parse_xattr_streams;
3772 #endif /* defined(HAVE_SUN_OS) */
3775 * Entry points when compiled with support for XATTRs on a supported platform.
3777 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3780 * See if we are changing from one device to an other.
3781 * We save the current device we are scanning and compare
3782 * it with the current st_dev in the last stat performed on
3783 * the file we are currently storing.
3785 if (jcr->xattr_data->current_dev != ff_pkt->statp.st_dev) {
3787 * Reset the acl save flags.
3789 jcr->xattr_data->flags = 0;
3790 jcr->xattr_data->flags |= BXATTR_FLAG_SAVE_NATIVE;
3793 * Save that we started scanning a new filesystem.
3795 jcr->xattr_data->current_dev = ff_pkt->statp.st_dev;
3798 if ((jcr->xattr_data->flags & BXATTR_FLAG_SAVE_NATIVE) && os_parse_xattr_streams) {
3799 return os_build_xattr_streams(jcr, ff_pkt);
3801 return bxattr_exit_ok;
3805 bxattr_exit_code parse_xattr_streams(JCR *jcr,
3808 uint32_t content_length)
3813 bxattr_exit_code retval = bxattr_exit_error;
3816 * See if we are changing from one device to an other.
3817 * We save the current device we are restoring to and compare
3818 * it with the current st_dev in the last stat performed on
3819 * the file we are currently restoring.
3821 ret = lstat(jcr->last_fname, &st);
3828 retval = bxattr_exit_ok;
3832 _("Unable to stat file \"%s\": ERR=%s\n"),
3833 jcr->last_fname, be.bstrerror());
3834 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
3835 jcr->last_fname, be.bstrerror());
3843 if (jcr->xattr_data->current_dev != st.st_dev) {
3845 * Reset the acl save flags.
3847 jcr->xattr_data->flags = 0;
3848 jcr->xattr_data->flags |= BXATTR_FLAG_RESTORE_NATIVE;
3851 * Save that we started restoring to a new filesystem.
3853 jcr->xattr_data->current_dev = st.st_dev;
3857 * See if we are still restoring native xattr to this filesystem.
3859 if ((jcr->xattr_data->flags & BXATTR_FLAG_RESTORE_NATIVE) && os_parse_xattr_streams) {
3861 * See if we can parse this stream, and ifso give it a try.
3863 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3864 if (os_default_xattr_streams[cnt] == stream) {
3865 retval = os_parse_xattr_streams(jcr, stream, content, content_length);
3871 * Increment error count but don't log an error again for the same filesystem.
3873 jcr->xattr_data->u.parse->nr_errors++;
3874 retval = bxattr_exit_ok;
3879 * Issue a warning and discard the message. But pretend the restore was ok.
3881 Jmsg2(jcr, M_WARNING, 0,
3882 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3883 jcr->last_fname, stream);