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 * - IRIX (Extended Attributes)
39 * - Linux (Extended Attributes)
40 * - NetBSD (Extended Attributes)
41 * - OpenBSD (Extended Attributes)
42 * (As it seems either they never implemented xattr or they are removed
43 * the support as it stated it was in version 3.1 but the current syscall
44 * tabled shows the extattr_ functions are not implemented. So as such we
45 * might eventually support xattr on OpenBSD when they implemented them using
46 * the same interface as FreeBSD and NetBSD.
47 * - Solaris (Extended Attributes and Extensible Attributes)
48 * - Tru64 (Extended Attributes)
50 * Written by Marco van Wieringen, November 2008
51 * Major overhaul January 2012
57 #if !defined(HAVE_XATTR)
59 * Entry points when compiled without support for XATTRs or on an unsupported platform.
61 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
63 return bxattr_exit_fatal;
66 bxattr_exit_code parse_xattr_streams(JCR *jcr,
69 uint32_t content_length)
71 return bxattr_exit_fatal;
75 * Send a XATTR stream to the SD.
77 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
79 BSOCK *sd = jcr->store_bsock;
81 #ifdef FD_NO_SEND_TEST
82 return bxattr_exit_ok;
88 if (jcr->xattr_data->u.build->content_length <= 0) {
89 return bxattr_exit_ok;
95 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
96 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
98 return bxattr_exit_fatal;
102 * Send the buffer to the storage deamon
104 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->u.build->content);
106 sd->msg = jcr->xattr_data->u.build->content;
107 sd->msglen = jcr->xattr_data->u.build->content_length;
111 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
113 return bxattr_exit_fatal;
116 jcr->JobBytes += sd->msglen;
118 if (!sd->signal(BNET_EOD)) {
119 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
121 return bxattr_exit_fatal;
123 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
124 return bxattr_exit_ok;
128 * First some generic functions for OSes that use the same xattr encoding scheme.
129 * Currently for all OSes except for Solaris.
131 #if !defined(HAVE_SUN_OS)
132 static void xattr_drop_internal_table(alist *xattr_value_list)
134 xattr_t *current_xattr;
137 * Walk the list of xattrs and free allocated memory on traversing.
139 foreach_alist(current_xattr, xattr_value_list) {
141 * See if we can shortcut.
143 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
146 free(current_xattr->name);
148 if (current_xattr->value_length > 0)
149 free(current_xattr->value);
154 delete xattr_value_list;
158 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
159 * which encodes one or more xattr_t structures.
161 * The Serialized stream consists of the following elements:
162 * magic - A magic string which makes it easy to detect any binary incompatabilites
163 * name_length - The length of the following xattr name
164 * name - The name of the extended attribute
165 * value_length - The length of the following xattr data
166 * value - The actual content of the extended attribute
168 * This is repeated 1 or more times.
171 static uint32_t serialize_xattr_stream(JCR *jcr,
172 uint32_t expected_serialize_len,
173 alist *xattr_value_list)
175 xattr_t *current_xattr;
179 * Make sure the serialized stream fits in the poolmem buffer.
180 * We allocate some more to be sure the stream is gonna fit.
182 jcr->xattr_data->u.build->content =
183 check_pool_memory_size(jcr->xattr_data->u.build->content,
184 expected_serialize_len + 10);
185 ser_begin(jcr->xattr_data->u.build->content,
186 expected_serialize_len + 10);
189 * Walk the list of xattrs and serialize the data.
191 foreach_alist(current_xattr, xattr_value_list) {
193 * See if we can shortcut.
195 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
198 ser_uint32(current_xattr->magic);
199 ser_uint32(current_xattr->name_length);
200 ser_bytes(current_xattr->name, current_xattr->name_length);
202 ser_uint32(current_xattr->value_length);
203 if (current_xattr->value_length > 0 && current_xattr->value) {
204 ser_bytes(current_xattr->value, current_xattr->value_length);
206 Dmsg3(100, "Backup xattr named %s, value %*s\n",
207 current_xattr->name, current_xattr->value, current_xattr->value);
209 Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
213 ser_end(jcr->xattr_data->u.build->content, expected_serialize_len + 10);
214 jcr->xattr_data->u.build->content_length =
215 ser_length(jcr->xattr_data->u.build->content);
217 return jcr->xattr_data->u.build->content_length;
220 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr,
222 uint32_t content_length,
223 alist *xattr_value_list)
226 xattr_t *current_xattr;
229 * Parse the stream and call restore_xattr_on_file for each extended attribute.
231 * Start unserializing the data. We keep on looping while we have not
232 * unserialized all bytes in the stream.
234 unser_begin(content, content_length);
235 while (unser_length(content) < content_length) {
237 * First make sure the magic is present. This way we can easily catch corruption.
238 * Any missing MAGIC is fatal we do NOT try to continue.
240 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
241 unser_uint32(current_xattr->magic);
242 if (current_xattr->magic != XATTR_MAGIC) {
244 _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
246 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
249 return bxattr_exit_error;
253 * Decode the valuepair. First decode the length of the name.
255 unser_uint32(current_xattr->name_length);
256 if (current_xattr->name_length == 0) {
258 _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
260 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
263 return bxattr_exit_error;
267 * Allocate room for the name and decode its content.
269 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
270 unser_bytes(current_xattr->name, current_xattr->name_length);
273 * The xattr_name needs to be null terminated.
275 current_xattr->name[current_xattr->name_length] = '\0';
278 * Decode the value length.
280 unser_uint32(current_xattr->value_length);
282 if (current_xattr->value_length > 0) {
284 * Allocate room for the value and decode its content.
286 current_xattr->value = (char *)malloc(current_xattr->value_length);
287 unser_bytes(current_xattr->value, current_xattr->value_length);
289 Dmsg3(100, "Restoring xattr named %s, value %*s\n",
290 current_xattr->name, current_xattr->value, current_xattr->value);
292 current_xattr->value = NULL;
293 Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
296 xattr_value_list->append(current_xattr);
299 unser_end(content, content_length);
300 return bxattr_exit_ok;
305 * This is a supported OS, See what kind of interface we should use.
307 #if defined(HAVE_AIX_OS)
309 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
310 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
311 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
312 #error "Missing full support for the Extended Attributes (EA) functions."
318 #error "Missing sys/ea.h header file"
322 * Define the supported XATTR streams for this OS
324 static int os_default_xattr_streams[1] = {
329 * Fallback to the non l-functions when those are not available.
331 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
334 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
337 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
338 #define llistea listea
341 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
344 char *xattr_list, *bp;
345 int cnt, xattr_count = 0;
346 uint32_t name_length;
347 int32_t xattr_list_len,
349 uint32_t expected_serialize_len = 0;
350 xattr_t *current_xattr = NULL;
351 alist *xattr_value_list = NULL;
352 bxattr_exit_code retval = bxattr_exit_error;
356 * First get the length of the available list with extended attributes.
358 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
359 switch (xattr_list_len) {
364 return bxattr_exit_ok;
367 * If the filesystem reports it doesn't support XATTRs we clear the
368 * BXATTR_FLAG_SAVE_NATIVE flag so we skip XATTR saves on all other files
369 * on the same filesystem. The BXATTR_FLAG_SAVE_NATIVE flags gets sets again
370 * when we change from one filesystem to an other.
372 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
373 return bxattr_exit_ok;
376 _("llistea error on file \"%s\": ERR=%s\n"),
377 jcr->last_fname, be.bstrerror());
378 Dmsg2(100, "llistea error file=%s ERR=%s\n",
379 jcr->last_fname, be.bstrerror());
380 return bxattr_exit_error;
384 return bxattr_exit_ok;
390 * Allocate room for the extented attribute list.
392 xattr_list = (char *)malloc(xattr_list_len + 1);
393 memset(xattr_list, 0, xattr_list_len + 1);
396 * Get the actual list of extended attributes names for a file.
398 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
399 switch (xattr_list_len) {
404 retval = bxattr_exit_ok;
408 _("llistea error on file \"%s\": ERR=%s\n"),
409 jcr->last_fname, be.bstrerror());
410 Dmsg2(100, "llistea error file=%s ERR=%s\n",
411 jcr->last_fname, be.bstrerror());
418 xattr_list[xattr_list_len] = '\0';
421 * Walk the list of extended attributes names and retrieve the data.
422 * We already count the bytes needed for serializing the stream later on.
425 while ((bp - xattr_list) + 1 < xattr_list_len) {
429 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
435 name_length = strlen(bp);
436 if (skip_xattr || name_length == 0) {
437 Dmsg1(100, "Skipping xattr named %s\n", bp);
438 bp = strchr(bp, '\0') + 1;
443 * Each xattr valuepair starts with a magic so we can parse it easier.
445 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
446 current_xattr->magic = XATTR_MAGIC;
447 expected_serialize_len += sizeof(current_xattr->magic);
450 * Allocate space for storing the name.
452 current_xattr->name_length = name_length;
453 current_xattr->name = (char *)malloc(current_xattr->name_length);
454 memcpy(current_xattr->name, bp, current_xattr->name_length);
456 expected_serialize_len += sizeof(current_xattr->name_length) +
457 current_xattr->name_length;
460 * First see how long the value is for the extended attribute.
462 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
463 switch (xattr_value_len) {
468 retval = bxattr_exit_ok;
472 _("lgetea error on file \"%s\": ERR=%s\n"),
473 jcr->last_fname, be.bstrerror());
474 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
475 jcr->last_fname, be.bstrerror());
480 current_xattr->value = NULL;
481 current_xattr->value_length = 0;
482 expected_serialize_len += sizeof(current_xattr->value_length);
486 * Allocate space for storing the value.
488 current_xattr->value = (char *)malloc(xattr_value_len);
489 memset(current_xattr->value, 0, xattr_value_len);
491 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
492 if (xattr_value_len < 0) {
496 retval = bxattr_exit_ok;
500 _("lgetea error on file \"%s\": ERR=%s\n"),
501 jcr->last_fname, be.bstrerror());
502 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
503 jcr->last_fname, be.bstrerror());
508 * Store the actual length of the value.
510 current_xattr->value_length = xattr_value_len;
511 expected_serialize_len += sizeof(current_xattr->value_length) +
512 current_xattr->value_length;
515 * Protect ourself against things getting out of hand.
517 if (expected_serialize_len >= MAX_XATTR_STREAM) {
519 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
520 jcr->last_fname, MAX_XATTR_STREAM);
526 if (xattr_value_list == NULL) {
527 xattr_value_list = New(alist(10, not_owned_by_alist));
530 xattr_value_list->append(current_xattr);
531 current_xattr = NULL;
533 bp = strchr(bp, '\0') + 1;
537 xattr_list = (char *)NULL;
540 * If we found any xattr send them to the SD.
542 if (xattr_count > 0) {
544 * Serialize the datastream.
546 if (serialize_xattr_stream(jcr,
547 expected_serialize_len,
548 xattr_value_list) < expected_serialize_len) {
550 _("Failed to serialize extended attributes on file \"%s\"\n"),
552 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
558 * Send the datastream to the SD.
560 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
562 retval = bxattr_exit_ok;
566 if (current_xattr != NULL) {
567 if (current_xattr->value != NULL) {
568 free(current_xattr->value);
570 if (current_xattr->name != NULL) {
571 free(current_xattr->name);
575 if (xattr_list != NULL) {
578 if (xattr_value_list != NULL) {
579 xattr_drop_internal_table(xattr_value_list);
584 static bxattr_exit_code aix_parse_xattr_streams(JCR *jcr,
587 uint32_t content_length)
589 xattr_t *current_xattr;
590 alist *xattr_value_list;
593 xattr_value_list = New(alist(10, not_owned_by_alist));
595 if (unserialize_xattr_stream(jcr,
598 xattr_value_list) != bxattr_exit_ok) {
599 xattr_drop_internal_table(xattr_value_list);
600 return bxattr_exit_error;
603 foreach_alist(current_xattr, xattr_value_list) {
604 if (lsetea(jcr->last_fname,
606 current_xattr->value,
607 current_xattr->value_length, 0) != 0) {
614 * If the filesystem reports it doesn't support XATTRs we clear
615 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
616 * on all other files on the same filesystem. The
617 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
618 * change from one filesystem to an other.
620 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
624 _("lsetea error on file \"%s\": ERR=%s\n"),
625 jcr->last_fname, be.bstrerror());
626 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
627 jcr->last_fname, be.bstrerror());
633 xattr_drop_internal_table(xattr_value_list);
634 return bxattr_exit_ok;
637 xattr_drop_internal_table(xattr_value_list);
638 return bxattr_exit_error;
642 * Function pointers to the build and parse function to use for these xattrs.
644 static bxattr_exit_code (*os_build_xattr_streams)
645 (JCR *jcr, FF_PKT *ff_pkt) =
646 aix_xattr_build_streams;
647 static bxattr_exit_code (*os_parse_xattr_streams)
648 (JCR *jcr, int stream, char *content, uint32_t content_length) =
649 aix_parse_xattr_streams;
651 #elif defined(HAVE_IRIX_OS)
653 #include <sys/attributes.h>
656 * Define the supported XATTR streams for this OS
658 static int os_default_xattr_streams[1] = {
661 static const char *xattr_acl_skiplist[1] = {
664 static const char *xattr_skiplist[1] = {
668 struct xattr_naming_space {
673 static xattr_naming_space xattr_naming_spaces[] = {
679 ATTR_ROOT | ATTR_DONTFOLLOW
686 static bxattr_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
688 int cnt, length, xattr_count = 0;
689 attrlist_cursor_t cursor;
690 attrlist_t *attrlist;
691 attrlist_ent_t *attrlist_ent;
692 xattr_t *current_xattr = NULL;
693 alist *xattr_value_list = NULL;
694 uint32_t expected_serialize_len = 0;
695 bxattr_exit_code retval = bxattr_exit_error;
696 POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
699 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
700 memset(&cursor, 0, sizeof(attrlist_cursor_t));
702 if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
703 xattr_naming_spaces[cnt].flags, &cursor) != 0) {
706 retval = bxattr_exit_ok;
710 _("attr_list error on file \"%s\": ERR=%s\n"),
711 jcr->last_fname, be.bstrerror());
712 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
713 jcr->last_fname, be.bstrerror());
718 attrlist = (attrlist_t *)xattrbuf;
721 * Walk the available attributes.
723 for (cnt = 0; cnt < attrlist->al_count; cnt++) {
724 attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
727 * Each xattr valuepair starts with a magic so we can parse it easier.
729 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
730 current_xattr->magic = XATTR_MAGIC;
731 expected_serialize_len += sizeof(current_xattr->magic);
734 * Allocate space for storing the name.
735 * We store the name as <naming_space_name><xattr_name>
737 current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) +
738 strlen(attrlist_ent->a_name) + 1;
739 current_xattr->name = (char *)malloc(current_xattr->name_length);
740 bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
741 xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
743 expected_serialize_len += sizeof(current_xattr->name_length) +
744 current_xattr->name_length;
746 current_xattr->value_length = attrlist_ent->a_valuelen;
747 current_xattr->value = (char *)malloc(current_xattr->value_length);
750 * Retrieve the actual value of the xattr.
752 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
753 &length, xattr_naming_spaces[cnt].flags) != 0) {
757 retval = bxattr_exit_ok;
761 * The buffer for the xattr isn't big enough. the value of
762 * current_xattr->value_length is updated with the actual size
763 * of the xattr. So we free the old buffer and create a new one
766 free(current_xattr->value);
767 current_xattr->value = (char *)malloc(current_xattr->value_length);
768 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
769 &length, xattr_naming_spaces[cnt].flags) != 0) {
773 retval = bxattr_exit_ok;
777 _("attr_list error on file \"%s\": ERR=%s\n"),
778 jcr->last_fname, be.bstrerror());
779 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
780 jcr->last_fname, be.bstrerror());
784 current_xattr->value_length = length;
789 _("attr_list error on file \"%s\": ERR=%s\n"),
790 jcr->last_fname, be.bstrerror());
791 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
792 jcr->last_fname, be.bstrerror());
796 current_xattr->value_length = length;
799 expected_serialize_len += sizeof(current_xattr->value_length) +
800 current_xattr->value_length;
803 * Protect ourself against things getting out of hand.
805 if (expected_serialize_len >= MAX_XATTR_STREAM) {
807 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
808 jcr->last_fname, MAX_XATTR_STREAM);
812 if (xattr_value_list == NULL) {
813 xattr_value_list = New(alist(10, not_owned_by_alist));
816 xattr_value_list->append(current_xattr);
817 current_xattr = NULL;
822 * See if there are more attributes available for a next run of attr_list.
824 if (attrlist->al_more == 0) {
831 * If we found any xattr send them to the SD.
833 if (xattr_count > 0) {
835 * Serialize the datastream.
837 if (serialize_xattr_stream(jcr,
838 expected_serialize_len,
839 xattr_value_list) < expected_serialize_len) {
841 _("Failed to serialize extended attributes on file \"%s\"\n"),
843 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
849 * Send the datastream to the SD.
851 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
853 retval = bxattr_exit_ok;
857 if (current_xattr != NULL) {
858 if (current_xattr->value != NULL) {
859 free(current_xattr->value);
861 if (current_xattr->name != NULL) {
862 free(current_xattr->name);
866 free_pool_memory(xattrbuf);
868 if (xattr_value_list != NULL) {
869 xattr_drop_internal_table(xattr_value_list);
874 static bxattr_exit_code irix_parse_xattr_streams(JCR *jcr,
877 uint32_t content_length)
880 int cnt, cmp_size, name_space_index, flags;
881 xattr_t *current_xattr;
882 alist *xattr_value_list;
883 bxattr_exit_code retval = bxattr_exit_error;
886 xattr_value_list = New(alist(10, not_owned_by_alist));
888 if (unserialize_xattr_stream(jcr,
891 xattr_value_list) != bxattr_exit_ok) {
892 xattr_drop_internal_table(xattr_value_list);
893 return bxattr_exit_error;
896 foreach_alist(current_xattr, xattr_value_list) {
898 * See to what namingspace this xattr belongs to.
900 name_space_index = 0;
901 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
902 cmp_size = strlen(xattr_naming_spaces[cnt].name);
903 if (!strncasecmp(current_xattr->name,
904 xattr_naming_spaces[cnt].name,
906 name_space_index = cnt;
912 * If we got a xattr that doesn't belong to an valid namespace complain.
914 if (name_space_index == 0) {
916 _("Received illegal xattr named %s on file \"%s\"\n"),
917 current_xattr->name, jcr->last_fname);
918 Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
919 current_xattr->name, jcr->last_fname);
924 * Restore the xattr first try to create the attribute from scratch.
926 flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
927 bp = strchr(current_xattr->name, '.');
928 if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
929 current_xattr->value_length, flags) != 0) {
932 retval = bxattr_exit_ok;
936 * The xattr already exists we need to replace it.
938 flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
939 if (attr_set(jcr->last_fname, bp, current_xattr->value,
940 current_xattr->value_length, flags) != 0) {
943 retval = bxattr_exit_ok;
947 _("attr_set error on file \"%s\": ERR=%s\n"),
948 jcr->last_fname, be.bstrerror());
949 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
950 jcr->last_fname, be.bstrerror());
957 _("attr_set error on file \"%s\": ERR=%s\n"),
958 jcr->last_fname, be.bstrerror());
959 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
960 jcr->last_fname, be.bstrerror());
966 xattr_drop_internal_table(xattr_value_list);
967 return bxattr_exit_ok;
970 xattr_drop_internal_table(xattr_value_list);
971 return bxattr_exit_error;
975 * Function pointers to the build and parse function to use for these xattrs.
977 static bxattr_exit_code (*os_build_xattr_streams)
978 (JCR *jcr, FF_PKT *ff_pkt) =
979 irix_xattr_build_streams;
980 static bxattr_exit_code (*os_parse_xattr_streams)
981 (JCR *jcr, int stream, char *content, uint32_t content_length) =
982 irix_parse_xattr_streams;
984 #elif defined(HAVE_DARWIN_OS) || \
985 defined(HAVE_LINUX_OS)
987 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
988 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
989 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
990 #error "Missing full support for the XATTR functions."
993 #ifdef HAVE_SYS_XATTR_H
994 #include <sys/xattr.h>
996 #error "Missing sys/xattr.h header file"
1000 * Define the supported XATTR streams for this OS
1002 #if defined(HAVE_DARWIN_OS)
1003 static int os_default_xattr_streams[1] = {
1006 static const char *xattr_acl_skiplist[2] = {
1007 "com.apple.system.Security",
1010 static const char *xattr_skiplist[3] = {
1011 "com.apple.system.extendedsecurity",
1012 "com.apple.ResourceFork",
1015 #elif defined(HAVE_LINUX_OS)
1016 static int os_default_xattr_streams[1] = {
1019 static const char *xattr_acl_skiplist[3] = {
1020 "system.posix_acl_access",
1021 "system.posix_acl_default",
1024 static const char *xattr_skiplist[1] = {
1030 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
1031 * listxattr, getxattr and setxattr with an extra options argument
1032 * which mimics the l variants of the functions when we specify
1033 * XATTR_NOFOLLOW as the options value.
1035 #if defined(HAVE_DARWIN_OS)
1036 #define llistxattr(path, list, size) \
1037 listxattr((path), (list), (size), XATTR_NOFOLLOW)
1038 #define lgetxattr(path, name, value, size) \
1039 getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
1040 #define lsetxattr(path, name, value, size, flags) \
1041 setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
1044 * Fallback to the non l-functions when those are not available.
1046 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
1047 #define lgetxattr getxattr
1049 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
1050 #define lsetxattr setxattr
1052 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
1053 #define llistxattr listxattr
1057 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
1060 char *xattr_list, *bp;
1061 int cnt, xattr_count = 0;
1062 uint32_t name_length;
1063 int32_t xattr_list_len,
1065 uint32_t expected_serialize_len = 0;
1066 xattr_t *current_xattr = NULL;
1067 alist *xattr_value_list = NULL;
1068 bxattr_exit_code retval = bxattr_exit_error;
1072 * First get the length of the available list with extended attributes.
1074 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
1075 switch (xattr_list_len) {
1079 return bxattr_exit_ok;
1080 case BXATTR_ENOTSUP:
1082 * If the filesystem reports it doesn't support XATTRs we clear
1083 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1084 * on all other files on the same filesystem. The
1085 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1086 * change from one filesystem to an other.
1088 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1089 return bxattr_exit_ok;
1092 _("llistxattr error on file \"%s\": ERR=%s\n"),
1093 jcr->last_fname, be.bstrerror());
1094 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1095 jcr->last_fname, be.bstrerror());
1096 return bxattr_exit_error;
1100 return bxattr_exit_ok;
1106 * Allocate room for the extented attribute list.
1108 xattr_list = (char *)malloc(xattr_list_len + 1);
1109 memset(xattr_list, 0, xattr_list_len + 1);
1112 * Get the actual list of extended attributes names for a file.
1114 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
1115 switch (xattr_list_len) {
1119 retval = bxattr_exit_ok;
1123 _("llistxattr error on file \"%s\": ERR=%s\n"),
1124 jcr->last_fname, be.bstrerror());
1125 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1126 jcr->last_fname, be.bstrerror());
1133 xattr_list[xattr_list_len] = '\0';
1136 * Walk the list of extended attributes names and retrieve the data.
1137 * We already count the bytes needed for serializing the stream later on.
1140 while ((bp - xattr_list) + 1 < xattr_list_len) {
1144 * On some OSes you also get the acls in the extented attribute list.
1145 * So we check if we are already backing up acls and if we do we
1146 * don't store the extended attribute with the same info.
1148 if (ff_pkt->flags & FO_ACL) {
1149 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1150 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1158 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1161 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1162 if (bstrcmp(bp, xattr_skiplist[cnt])) {
1169 name_length = strlen(bp);
1170 if (skip_xattr || name_length == 0) {
1171 Dmsg1(100, "Skipping xattr named %s\n", bp);
1172 bp = strchr(bp, '\0') + 1;
1177 * Each xattr valuepair starts with a magic so we can parse it easier.
1179 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1180 current_xattr->magic = XATTR_MAGIC;
1181 expected_serialize_len += sizeof(current_xattr->magic);
1184 * Allocate space for storing the name.
1186 current_xattr->name_length = name_length;
1187 current_xattr->name = (char *)malloc(current_xattr->name_length);
1188 memcpy(current_xattr->name, bp, current_xattr->name_length);
1190 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1193 * First see how long the value is for the extended attribute.
1195 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1196 switch (xattr_value_len) {
1200 retval = bxattr_exit_ok;
1204 _("lgetxattr error on file \"%s\": ERR=%s\n"),
1205 jcr->last_fname, be.bstrerror());
1206 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1207 jcr->last_fname, be.bstrerror());
1212 current_xattr->value = NULL;
1213 current_xattr->value_length = 0;
1214 expected_serialize_len += sizeof(current_xattr->value_length);
1218 * Allocate space for storing the value.
1220 current_xattr->value = (char *)malloc(xattr_value_len);
1221 memset(current_xattr->value, 0, xattr_value_len);
1223 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1224 if (xattr_value_len < 0) {
1227 retval = bxattr_exit_ok;
1231 _("lgetxattr error on file \"%s\": ERR=%s\n"),
1232 jcr->last_fname, be.bstrerror());
1233 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1234 jcr->last_fname, be.bstrerror());
1239 * Store the actual length of the value.
1241 current_xattr->value_length = xattr_value_len;
1242 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1245 * Protect ourself against things getting out of hand.
1247 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1249 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1250 jcr->last_fname, MAX_XATTR_STREAM);
1255 if (xattr_value_list == NULL) {
1256 xattr_value_list = New(alist(10, not_owned_by_alist));
1259 xattr_value_list->append(current_xattr);
1260 current_xattr = NULL;
1262 bp = strchr(bp, '\0') + 1;
1267 xattr_list = (char *)NULL;
1270 * If we found any xattr send them to the SD.
1272 if (xattr_count > 0) {
1274 * Serialize the datastream.
1276 if (serialize_xattr_stream(jcr,
1277 expected_serialize_len,
1278 xattr_value_list) < expected_serialize_len) {
1280 _("Failed to serialize extended attributes on file \"%s\"\n"),
1282 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1288 * Send the datastream to the SD.
1290 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1292 retval = bxattr_exit_ok;
1296 if (current_xattr != NULL) {
1297 if (current_xattr->value != NULL) {
1298 free(current_xattr->value);
1300 if (current_xattr->name != NULL) {
1301 free(current_xattr->name);
1303 free(current_xattr);
1305 if (xattr_list != NULL) {
1308 if (xattr_value_list != NULL) {
1309 xattr_drop_internal_table(xattr_value_list);
1314 static bxattr_exit_code generic_parse_xattr_streams(JCR *jcr,
1317 uint32_t content_length)
1319 xattr_t *current_xattr;
1320 alist *xattr_value_list;
1323 xattr_value_list = New(alist(10, not_owned_by_alist));
1325 if (unserialize_xattr_stream(jcr,
1328 xattr_value_list) != bxattr_exit_ok) {
1329 xattr_drop_internal_table(xattr_value_list);
1330 return bxattr_exit_error;
1333 foreach_alist(current_xattr, xattr_value_list) {
1334 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1338 case BXATTR_ENOTSUP:
1340 * If the filesystem reports it doesn't support XATTRs we clear
1341 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1342 * on all other files on the same filesystem. The
1343 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1344 * change from one filesystem to an other.
1346 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
1350 _("lsetxattr error on file \"%s\": ERR=%s\n"),
1351 jcr->last_fname, be.bstrerror());
1352 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1353 jcr->last_fname, be.bstrerror());
1359 xattr_drop_internal_table(xattr_value_list);
1360 return bxattr_exit_ok;
1363 xattr_drop_internal_table(xattr_value_list);
1364 return bxattr_exit_error;
1368 * Function pointers to the build and parse function to use for these xattrs.
1370 static bxattr_exit_code (*os_build_xattr_streams)
1371 (JCR *jcr, FF_PKT *ff_pkt) =
1372 generic_xattr_build_streams;
1373 static bxattr_exit_code (*os_parse_xattr_streams)
1374 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1375 generic_parse_xattr_streams;
1377 #elif defined(HAVE_FREEBSD_OS) || \
1378 defined(HAVE_NETBSD_OS) || \
1379 defined(HAVE_OPENBSD_OS)
1381 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1382 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1383 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1384 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1385 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1386 #error "Missing full support for the extattr functions."
1389 #ifdef HAVE_SYS_EXTATTR_H
1390 #include <sys/extattr.h>
1392 #error "Missing sys/extattr.h header file"
1395 #ifdef HAVE_LIBUTIL_H
1396 #include <libutil.h>
1399 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1400 #define extattr_get_link extattr_get_file
1402 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1403 #define extattr_set_link extattr_set_file
1405 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1406 #define extattr_list_link extattr_list_file
1409 #if defined(HAVE_FREEBSD_OS)
1410 static int os_default_xattr_streams[1] = {
1411 STREAM_XATTR_FREEBSD
1413 static int os_default_xattr_namespaces[2] = {
1414 EXTATTR_NAMESPACE_USER,
1415 EXTATTR_NAMESPACE_SYSTEM
1417 static const char *xattr_acl_skiplist[4] = {
1418 "system.posix1e.acl_access",
1419 "system.posix1e.acl_default",
1423 static const char *xattr_skiplist[1] = {
1426 #elif defined(HAVE_NETBSD_OS)
1427 static int os_default_xattr_streams[1] = {
1430 static int os_default_xattr_namespaces[2] = {
1431 EXTATTR_NAMESPACE_USER,
1432 EXTATTR_NAMESPACE_SYSTEM
1434 static const char *xattr_acl_skiplist[1] = {
1437 static const char *xattr_skiplist[1] = {
1440 #elif defined(HAVE_OPENBSD_OS)
1441 static int os_default_xattr_streams[1] = {
1442 STREAM_XATTR_OPENBSD
1444 static int os_default_xattr_namespaces[2] = {
1445 EXTATTR_NAMESPACE_USER,
1446 EXTATTR_NAMESPACE_SYSTEM
1448 static const char *xattr_acl_skiplist[1] = {
1451 static const char *xattr_skiplist[1] = {
1456 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1460 int cnt, index, xattr_count = 0;
1461 int32_t xattr_list_len,
1463 uint32_t expected_serialize_len = 0;
1464 unsigned int namespace_index;
1466 char *current_attrnamespace = NULL;
1467 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1468 xattr_t *current_xattr = NULL;
1469 alist *xattr_value_list = NULL;
1470 bxattr_exit_code retval = bxattr_exit_error;
1474 * Loop over all available xattr namespaces.
1476 for (namespace_index = 0;
1477 namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int);
1478 namespace_index++) {
1479 attrnamespace = os_default_xattr_namespaces[namespace_index];
1482 * First get the length of the available list with extended attributes.
1483 * If we get EPERM on system namespace, don't return error.
1484 * This is expected for normal users trying to archive the system
1485 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1486 * they've decided to return EOPNOTSUPP instead.
1488 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1489 switch (xattr_list_len) {
1493 retval = bxattr_exit_ok;
1495 #if defined(EOPNOTSUPP)
1499 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1507 _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1508 jcr->last_fname, be.bstrerror());
1509 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1510 jcr->last_fname, be.bstrerror());
1521 * Allocate room for the extented attribute list.
1523 xattr_list = (char *)malloc(xattr_list_len + 1);
1524 memset(xattr_list, 0, xattr_list_len + 1);
1527 * Get the actual list of extended attributes names for a file.
1529 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace,
1530 xattr_list, xattr_list_len);
1531 switch (xattr_list_len) {
1535 retval = bxattr_exit_ok;
1539 _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1540 jcr->last_fname, be.bstrerror());
1541 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1542 jcr->last_fname, be.bstrerror());
1549 xattr_list[xattr_list_len] = '\0';
1552 * Convert the numeric attrnamespace into a string representation and make
1553 * a private copy of that string. The extattr_namespace_to_string functions
1554 * returns a strdupped string which we need to free.
1556 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1558 _("Failed to convert %d into namespace on file \"%s\"\n"),
1559 attrnamespace, jcr->last_fname);
1560 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1561 attrnamespace, jcr->last_fname);
1566 * Walk the list of extended attributes names and retrieve the data.
1567 * We already count the bytes needed for serializing the stream later on.
1569 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1573 * Print the current name into the buffer as its not null terminated
1574 * we need to use the length encoded in the string for copying only
1577 cnt = xattr_list[index];
1578 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1579 cnt = ((int)sizeof(current_attrname) - 1);
1581 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1582 current_attrname[cnt] = '\0';
1585 * First make a xattr tuple of the current namespace and the name of
1586 * the xattr. e.g. something like user.<attrname> or system.<attrname>
1588 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s",
1589 current_attrnamespace, current_attrname);
1592 * On some OSes you also get the acls in the extented attribute list.
1593 * So we check if we are already backing up acls and if we do we
1594 * don't store the extended attribute with the same info.
1596 if (ff_pkt->flags & FO_ACL) {
1597 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1598 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1606 * On some OSes we want to skip certain xattrs which are in the
1607 * xattr_skiplist array.
1610 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1611 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1619 Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1624 * Each xattr valuepair starts with a magic so we can parse it easier.
1626 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1627 current_xattr->magic = XATTR_MAGIC;
1628 expected_serialize_len += sizeof(current_xattr->magic);
1631 * Allocate space for storing the name.
1633 current_xattr->name_length = strlen(current_attrtuple);
1634 current_xattr->name = (char *)malloc(current_xattr->name_length);
1635 memcpy(current_xattr->name, current_attrtuple, current_xattr->name_length);
1637 expected_serialize_len += sizeof(current_xattr->name_length) +
1638 current_xattr->name_length;
1641 * First see how long the value is for the extended attribute.
1643 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1644 current_attrname, NULL, 0);
1645 switch (xattr_value_len) {
1649 retval = bxattr_exit_ok;
1653 _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1654 jcr->last_fname, be.bstrerror());
1655 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1656 jcr->last_fname, be.bstrerror());
1661 current_xattr->value = NULL;
1662 current_xattr->value_length = 0;
1663 expected_serialize_len += sizeof(current_xattr->value_length);
1667 * Allocate space for storing the value.
1669 current_xattr->value = (char *)malloc(xattr_value_len);
1670 memset(current_xattr->value, 0, xattr_value_len);
1672 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1673 current_attrname, current_xattr->value,
1675 if (xattr_value_len < 0) {
1678 retval = bxattr_exit_ok;
1682 _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1683 jcr->last_fname, be.bstrerror());
1684 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1685 jcr->last_fname, be.bstrerror());
1691 * Store the actual length of the value.
1693 current_xattr->value_length = xattr_value_len;
1694 expected_serialize_len += sizeof(current_xattr->value_length) +
1695 current_xattr->value_length;
1698 * Protect ourself against things getting out of hand.
1700 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1702 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1703 jcr->last_fname, MAX_XATTR_STREAM);
1709 if (xattr_value_list == NULL) {
1710 xattr_value_list = New(alist(10, not_owned_by_alist));
1713 xattr_value_list->append(current_xattr);
1714 current_xattr = NULL;
1720 * Drop the local copy of the current_attrnamespace.
1722 actuallyfree(current_attrnamespace);
1723 current_attrnamespace = NULL;
1726 * We are done with this xattr list.
1729 xattr_list = (char *)NULL;
1733 * If we found any xattr send them to the SD.
1735 if (xattr_count > 0) {
1737 * Serialize the datastream.
1739 if (serialize_xattr_stream(jcr,
1740 expected_serialize_len,
1741 xattr_value_list) < expected_serialize_len) {
1743 _("Failed to serialize extended attributes on file \"%s\"\n"),
1745 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1751 * Send the datastream to the SD.
1753 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1755 retval = bxattr_exit_ok;
1759 if (current_attrnamespace != NULL) {
1760 actuallyfree(current_attrnamespace);
1762 if (current_xattr != NULL) {
1763 if (current_xattr->value != NULL) {
1764 free(current_xattr->value);
1766 if (current_xattr->name != NULL) {
1767 free(current_xattr->name);
1769 free(current_xattr);
1771 if (xattr_list != NULL) {
1774 if (xattr_value_list != NULL) {
1775 xattr_drop_internal_table(xattr_value_list);
1780 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr,
1783 uint32_t content_length)
1785 xattr_t *current_xattr;
1786 alist *xattr_value_list;
1787 int current_attrnamespace, cnt;
1788 char *attrnamespace, *attrname;
1791 xattr_value_list = New(alist(10, not_owned_by_alist));
1793 if (unserialize_xattr_stream(jcr,
1796 xattr_value_list) != bxattr_exit_ok) {
1797 xattr_drop_internal_table(xattr_value_list);
1798 return bxattr_exit_error;
1801 foreach_alist(current_xattr, xattr_value_list) {
1803 * Try splitting the xattr_name into a namespace and name part.
1804 * The splitting character is a .
1806 attrnamespace = current_xattr->name;
1807 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1809 _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1810 current_xattr->name, jcr->last_fname);
1811 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1812 current_xattr->name, jcr->last_fname);
1818 * Make sure the attrnamespace makes sense.
1820 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1822 _("Failed to convert %s into namespace on file \"%s\"\n"),
1823 attrnamespace, jcr->last_fname);
1824 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1825 attrnamespace, jcr->last_fname);
1830 * Try restoring the extended attribute.
1832 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1833 attrname, current_xattr->value, current_xattr->value_length);
1834 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1841 _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1842 jcr->last_fname, be.bstrerror());
1843 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1844 jcr->last_fname, be.bstrerror());
1851 xattr_drop_internal_table(xattr_value_list);
1852 return bxattr_exit_ok;
1855 xattr_drop_internal_table(xattr_value_list);
1856 return bxattr_exit_error;
1860 * Function pointers to the build and parse function to use for these xattrs.
1862 static bxattr_exit_code (*os_build_xattr_streams)
1863 (JCR *jcr, FF_PKT *ff_pkt) =
1864 bsd_build_xattr_streams;
1865 static bxattr_exit_code (*os_parse_xattr_streams)
1866 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1867 bsd_parse_xattr_streams;
1869 #elif defined(HAVE_OSF1_OS)
1871 #if !defined(HAVE_GETPROPLIST) || \
1872 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1873 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1874 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1875 !defined(HAVE_SETPROPLIST)
1876 #error "Missing full support for the Extended Attributes functions."
1879 #ifdef HAVE_SYS_PROPLIST_H
1880 #include <sys/proplist.h>
1882 #error "Missing sys/proplist.h header file"
1886 * Define the supported XATTR streams for this OS
1888 static int os_default_xattr_streams[1] = {
1891 static const char *xattr_acl_skiplist[1] = {
1894 static const char *xattr_skiplist[1] = {
1898 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1905 int xattr_count = 0;
1908 int32_t xattr_list_len,
1911 uint32_t expected_serialize_len = 0;
1912 xattr_t *current_xattr = NULL;
1913 alist *xattr_value_list = NULL;
1914 struct proplistname_args prop_args;
1915 bxattr_exit_code retval = bxattr_exit_error;
1916 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1919 xattrbuf_size = sizeof_pool_memory(xattrbuf);
1920 xattrbuf_min_size = 0;
1921 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1922 xattrbuf, &xattrbuf_min_size);
1925 * See what xattr are available.
1927 switch (xattr_list_len) {
1932 * If the filesystem reports it doesn't support XATTRs we clear
1933 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1934 * on all other files on the same filesystem. The
1935 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1936 * change from one filesystem to an other.
1938 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1939 retval = bxattr_exit_ok;
1943 _("getproplist error on file \"%s\": ERR=%s\n"),
1944 jcr->last_fname, be.bstrerror());
1945 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1946 jcr->last_fname, be.bstrerror());
1951 if (xattrbuf_min_size) {
1953 * The buffer isn't big enough to hold the xattr data, we now have
1954 * a minimum buffersize so we resize the buffer and try again.
1956 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1957 xattrbuf_size = xattrbuf_min_size + 1;
1958 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1959 xattrbuf, &xattrbuf_min_size);
1960 switch (xattr_list_len) {
1965 _("getproplist error on file \"%s\": ERR=%s\n"),
1966 jcr->last_fname, be.bstrerror());
1967 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1968 jcr->last_fname, be.bstrerror());
1974 * This should never happen as we sized the buffer according to the minimumsize
1975 * returned by a previous getproplist call. If it does happen things are fishy and
1976 * we are better of forgetting this xattr as it seems its list is changing at this
1977 * exact moment so we can never make a good backup copy of it.
1979 retval = bxattr_exit_ok;
1988 retval = bxattr_exit_ok;
1997 * Walk the list of extended attributes names and retrieve the data.
1998 * We already count the bytes needed for serializing the stream later on.
2001 while (xattrbuf_size > 0) {
2003 * Call getproplist_entry to initialize name and value
2004 * pointers to entries position within buffer.
2006 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
2009 * On some OSes you also get the acls in the extented attribute list.
2010 * So we check if we are already backing up acls and if we do we
2011 * don't store the extended attribute with the same info.
2013 if (ff_pkt->flags & FO_ACL) {
2014 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
2015 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
2023 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
2026 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
2027 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
2035 Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
2040 * Each xattr valuepair starts with a magic so we can parse it easier.
2042 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
2043 current_xattr->magic = XATTR_MAGIC;
2044 expected_serialize_len += sizeof(current_xattr->magic);
2046 current_xattr->name_length = strlen(xattr_name);
2047 current_xattr->name = bstrdup(xattr_name);
2049 expected_serialize_len += sizeof(current_xattr->name_length) +
2050 current_xattr->name_length;
2052 current_xattr->value_length = *xattr_value_len;
2053 current_xattr->value = (char *)malloc(current_xattr->value_length);
2054 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
2056 expected_serialize_len += sizeof(current_xattr->value_length) +
2057 current_xattr->value_length;
2060 * Protect ourself against things getting out of hand.
2062 if (expected_serialize_len >= MAX_XATTR_STREAM) {
2064 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2065 jcr->last_fname, MAX_XATTR_STREAM);
2069 if (xattr_value_list == NULL) {
2070 xattr_value_list = New(alist(10, not_owned_by_alist));
2073 xattr_value_list->append(current_xattr);
2074 current_xattr = NULL;
2079 * If we found any xattr send them to the SD.
2081 if (xattr_count > 0) {
2083 * Serialize the datastream.
2085 if (serialize_xattr_stream(jcr,
2086 expected_serialize_len,
2087 xattr_value_list) < expected_serialize_len) {
2089 _("Failed to serialize extended attributes on file \"%s\"\n"),
2091 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
2097 * Send the datastream to the SD.
2099 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
2101 retval = bxattr_exit_ok;
2105 if (current_xattr != NULL) {
2106 if (current_xattr->value != NULL) {
2107 free(current_xattr->value);
2109 if (current_xattr->name != NULL) {
2110 free(current_xattr->name);
2112 free(current_xattr);
2114 if (xattr_value_list != NULL) {
2115 xattr_drop_internal_table(xattr_value_list);
2117 free_pool_memory(xattrbuf);
2122 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr,
2125 uint32_t content_length)
2127 char *bp, *xattrbuf = NULL;
2128 int32_t xattrbuf_size, cnt;
2129 xattr_t *current_xattr;
2130 alist *xattr_value_list;
2131 bxattr_exit_code retval = bxattr_exit_error;
2134 xattr_value_list = New(alist(10, not_owned_by_alist));
2136 if (unserialize_xattr_stream(jcr,
2139 xattr_value_list) != bxattr_exit_ok) {
2140 xattr_drop_internal_table(xattr_value_list);
2141 return bxattr_exit_error;
2145 * See how big the propertylist must be.
2148 foreach_alist(current_xattr, xattr_value_list) {
2149 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
2152 xattrbuf = (char *)malloc(xattrbuf_size);
2155 * Add all value pairs to the proplist.
2159 foreach_alist(current_xattr, xattr_value_list) {
2160 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
2161 current_xattr->value, &bp);
2167 if (cnt != xattrbuf_size) {
2169 _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
2171 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
2177 * Restore the list of extended attributes on the file.
2179 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
2185 * If the filesystem reports it doesn't support XATTRs we clear
2186 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
2187 * on all other files on the same filesystem. The
2188 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
2189 * change from one filesystem to an other.
2191 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
2192 retval = bxattr_exit_ok;
2196 _("setproplist error on file \"%s\": ERR=%s\n"),
2197 jcr->last_fname, be.bstrerror());
2198 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
2199 jcr->last_fname, be.bstrerror());
2209 xattr_drop_internal_table(xattr_value_list);
2210 return bxattr_exit_ok;
2216 xattr_drop_internal_table(xattr_value_list);
2217 return bxattr_exit_error;
2221 * Function pointers to the build and parse function to use for these xattrs.
2223 static bxattr_exit_code (*os_build_xattr_streams)
2224 (JCR *jcr, FF_PKT *ff_pkt) =
2225 tru64_build_xattr_streams;
2226 static bxattr_exit_code (*os_parse_xattr_streams)
2227 (JCR *jcr, int stream, char *content, uint32_t content_length) =
2228 tru64_parse_xattr_streams;
2230 #elif defined(HAVE_SUN_OS)
2232 * Solaris extended attributes were introduced in Solaris 9
2235 * Solaris extensible attributes were introduced in OpenSolaris
2236 * by PSARC 2007/315 Solaris extensible attributes are also
2237 * sometimes called extended system attributes.
2239 * man fsattr(5) on Solaris gives a wealth of info. The most
2240 * important bits are:
2242 * Attributes are logically supported as files within the file
2243 * system. The file system is therefore augmented with an
2244 * orthogonal name space of file attributes. Any file (includ-
2245 * ing attribute files) can have an arbitrarily deep attribute
2246 * tree associated with it. Attribute values are accessed by
2247 * file descriptors obtained through a special attribute inter-
2248 * face. This logical view of "attributes as files" allows the
2249 * leveraging of existing file system interface functionality
2250 * to support the construction, deletion, and manipulation of
2253 * The special files "." and ".." retain their accustomed
2254 * semantics within the attribute hierarchy. The "." attribute
2255 * file refers to the current directory and the ".." attribute
2256 * file refers to the parent directory. The unnamed directory
2257 * at the head of each attribute tree is considered the "child"
2258 * of the file it is associated with and the ".." file refers
2259 * to the associated file. For any non-directory file with
2260 * attributes, the ".." entry in the unnamed directory refers
2261 * to a file that is not a directory.
2263 * Conceptually, the attribute model is fully general. Extended
2264 * attributes can be any type of file (doors, links, direc-
2265 * tories, and so forth) and can even have their own attributes
2266 * (fully recursive). As a result, the attributes associated
2267 * with a file could be an arbitrarily deep directory hierarchy
2268 * where each attribute could have an equally complex attribute
2269 * tree associated with it. Not all implementations are able
2270 * to, or want to, support the full model. Implementation are
2271 * therefore permitted to reject operations that are not sup-
2272 * ported. For example, the implementation for the UFS file
2273 * system allows only regular files as attributes (for example,
2274 * no sub-directories) and rejects attempts to place attributes
2277 * The following list details the operations that are rejected
2278 * in the current implementation:
2280 * link Any attempt to create links between
2281 * attribute and non-attribute space
2282 * is rejected to prevent security-
2283 * related or otherwise sensitive
2284 * attributes from being exposed, and
2285 * therefore manipulable, as regular
2288 * rename Any attempt to rename between
2289 * attribute and non-attribute space
2290 * is rejected to prevent an already
2291 * linked file from being renamed and
2292 * thereby circumventing the link res-
2295 * mkdir, symlink, mknod Any attempt to create a "non-
2296 * regular" file in attribute space is
2297 * rejected to reduce the functional-
2298 * ity, and therefore exposure and
2299 * risk, of the initial implementa-
2302 * The entire available name space has been allocated to "gen-
2303 * eral use" to bring the implementation in line with the NFSv4
2304 * draft standard [NFSv4]. That standard defines "named attri-
2305 * butes" (equivalent to Solaris Extended Attributes) with no
2306 * naming restrictions. All Sun applications making use of
2307 * opaque extended attributes will use the prefix "SUNW".
2310 #ifdef HAVE_SYS_ATTR_H
2311 #include <sys/attr.h>
2318 #ifdef HAVE_SYS_NVPAIR_H
2319 #include <sys/nvpair.h>
2322 #ifdef HAVE_SYS_ACL_H
2323 #include <sys/acl.h>
2326 #if !defined(HAVE_OPENAT) || \
2327 !defined(HAVE_UNLINKAT) || \
2328 !defined(HAVE_FCHOWNAT) || \
2329 !defined(HAVE_FUTIMESAT)
2330 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2334 * Define the supported XATTR streams for this OS
2336 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2337 static int os_default_xattr_streams[2] = {
2338 STREAM_XATTR_SOLARIS,
2339 STREAM_XATTR_SOLARIS_SYS
2342 static int os_default_xattr_streams[1] = {
2343 STREAM_XATTR_SOLARIS
2345 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2348 * This code creates a temporary cache with entries for each xattr which has
2349 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2351 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2353 xattr_link_cache_entry_t *ptr;
2355 foreach_alist(ptr, jcr->xattr_data->u.build->link_cache) {
2356 if (ptr && ptr->inum == inum) {
2363 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2365 xattr_link_cache_entry_t *ptr;
2367 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2368 memset(ptr, 0, sizeof(xattr_link_cache_entry_t));
2370 bstrncpy(ptr->target, target, sizeof(ptr->target));
2372 if (!jcr->xattr_data->u.build->link_cache) {
2373 jcr->xattr_data->u.build->link_cache = New(alist(10, not_owned_by_alist));
2375 jcr->xattr_data->u.build->link_cache->append(ptr);
2378 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2380 * This function returns true if a non default extended system attribute
2381 * list is associated with fd and returns false when an error has occured
2382 * or when only extended system attributes other than archive,
2383 * av_modified or crtime are set.
2385 * The function returns true for the following cases:
2387 * - any extended system attribute other than the default attributes
2388 * ('archive', 'av_modified' and 'crtime') is set
2389 * - nvlist has NULL name string
2390 * - nvpair has data type of 'nvlist'
2391 * - default data type.
2393 static bool solaris_has_non_transient_extensible_attributes(int fd)
2401 bool retval = false;
2403 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2408 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2409 name = nvpair_name(pair);
2412 fattr = name_to_attr(name);
2418 type = nvpair_type(pair);
2420 case DATA_TYPE_BOOLEAN_VALUE:
2421 if (nvpair_value_boolean_value(pair, &value) != 0) {
2424 if (value && fattr != F_ARCHIVE &&
2425 fattr != F_AV_MODIFIED) {
2430 case DATA_TYPE_UINT64_ARRAY:
2431 if (fattr != F_CRTIME) {
2436 case DATA_TYPE_NVLIST:
2444 if (response != NULL) {
2445 nvlist_free(response);
2449 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2451 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2453 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2454 * There is no need to store those acls as we already store the stat bits too.
2456 static bool acl_is_trivial(int count, aclent_t *entries)
2461 for (n = 0; n < count; n++) {
2463 if (!(ace->a_type == USER_OBJ ||
2464 ace->a_type == GROUP_OBJ ||
2465 ace->a_type == OTHER_OBJ ||
2466 ace->a_type == CLASS_OBJ))
2471 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2473 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2476 #ifdef HAVE_EXTENDED_ACL
2482 * See if this attribute has an ACL
2484 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2485 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2487 * See if there is a non trivial acl on the file.
2489 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2490 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2493 return bxattr_exit_ok;
2496 _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2497 attrname, jcr->last_fname, be.bstrerror());
2498 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2499 attrname, jcr->last_fname, be.bstrerror());
2500 return bxattr_exit_error;
2505 #if defined(ACL_SID_FMT)
2507 * New format flag added in newer Solaris versions.
2509 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2511 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2512 #endif /* ACL_SID_FMT */
2514 *acl_text = acl_totext(aclp, flags);
2522 return bxattr_exit_ok;
2523 #else /* HAVE_EXTENDED_ACL */
2525 aclent_t *acls = NULL;
2529 * See if this attribute has an ACL
2532 n = facl(fd, GETACLCNT, 0, NULL);
2534 n = acl(attrname, GETACLCNT, 0, NULL);
2537 if (n >= MIN_ACL_ENTRIES) {
2538 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2539 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2540 acl(attrname, GETACL, n, acls) != n) {
2544 return bxattr_exit_ok;
2547 _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2548 attrname, jcr->last_fname, be.bstrerror());
2549 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2550 attrname, jcr->last_fname, be.bstrerror());
2552 return bxattr_exit_error;
2557 * See if there is a non trivial acl on the file.
2559 if (!acl_is_trivial(n, acls)) {
2560 if ((*acl_text = acltotext(acls, n)) == NULL) {
2562 _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2563 attrname, jcr->last_fname, be.bstrerror());
2564 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2565 attrname, jcr->last_fname, be.bstrerror());
2567 return bxattr_exit_error;
2577 return bxattr_exit_ok;
2578 #endif /* HAVE_EXTENDED_ACL */
2580 #else /* HAVE_ACL */
2581 return bxattr_exit_ok;
2582 #endif /* HAVE_ACL */
2586 * Forward declaration for recursive function call.
2588 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2591 * Save an extended or extensible attribute.
2592 * This is stored as an opaque stream of bytes with the following encoding:
2594 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2596 * or for a hardlinked or symlinked attribute
2598 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2600 * xattr_name can be a subpath relative to the file the xattr is on.
2601 * stat_buffer is the string representation of the stat struct.
2602 * acl_string is an acl text when a non trivial acl is set on the xattr.
2603 * actual_xattr_data is the content of the xattr file.
2605 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2606 const char *attrname, bool toplevel_hidden_dir, int stream)
2611 xattr_link_cache_entry_t *xlce;
2612 char target_attrname[PATH_MAX];
2613 char link_source[PATH_MAX];
2614 char *acl_text = NULL;
2615 char attribs[MAXSTRING];
2616 char buffer[XATTR_BUFSIZ];
2617 bxattr_exit_code retval = bxattr_exit_error;
2620 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2623 * Get the stats of the extended or extensible attribute.
2625 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2628 retval = bxattr_exit_ok;
2632 _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2633 target_attrname, jcr->last_fname, be.bstrerror());
2634 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2635 target_attrname, jcr->last_fname, be.bstrerror());
2641 * Based on the filetype perform the correct action. We support most filetypes here, more
2642 * then the actual implementation on Solaris supports so some code may never get executed
2643 * due to limitations in the implementation.
2645 switch (st.st_mode & S_IFMT) {
2650 * Get any acl on the xattr.
2652 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2656 * The current implementation of xattr on Solaris doesn't support this,
2657 * but if it ever does we are prepared.
2658 * Encode the stat struct into an ASCII representation.
2660 encode_stat(attribs, &st, sizeof(st), 0, stream);
2661 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2662 target_attrname, 0, attribs, 0,
2663 (acl_text) ? acl_text : "", 0);
2667 * Get any acl on the xattr.
2669 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2673 * See if this is the toplevel_hidden_dir being saved.
2675 if (toplevel_hidden_dir) {
2677 * Save the data for later storage when we encounter a real xattr.
2678 * We store the data in the jcr->xattr_data->u.build->content buffer
2679 * and flush that just before sending out the first real xattr.
2680 * Encode the stat struct into an ASCII representation and jump
2681 * out of the function.
2683 encode_stat(attribs, &st, sizeof(st), 0, stream);
2684 cnt = bsnprintf(buffer, sizeof(buffer),
2686 target_attrname, 0, attribs, 0,
2687 (acl_text) ? acl_text : "", 0);
2688 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2689 jcr->xattr_data->u.build->content_length = cnt;
2693 * The current implementation of xattr on Solaris doesn't support this,
2694 * but if it ever does we are prepared.
2695 * Encode the stat struct into an ASCII representation.
2697 encode_stat(attribs, &st, sizeof(st), 0, stream);
2698 cnt = bsnprintf(buffer, sizeof(buffer),
2700 target_attrname, 0, attribs, 0,
2701 (acl_text) ? acl_text : "", 0);
2706 * If this is a hardlinked file check the inode cache for a hit.
2708 if (st.st_nlink > 1) {
2710 * See if the cache already knows this inode number.
2712 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2714 * Generate a xattr encoding with the reference to the target in there.
2716 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2717 cnt = bsnprintf(buffer, sizeof(buffer),
2719 target_attrname, 0, attribs, 0, xlce->target, 0);
2720 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2721 jcr->xattr_data->u.build->content_length = cnt;
2722 retval = send_xattr_stream(jcr, stream);
2725 * For a hard linked file we are ready now, no need to recursively
2726 * save the attributes.
2732 * Store this hard linked file in the cache.
2733 * Store the name relative to the top level xattr space.
2735 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2739 * Get any acl on the xattr.
2741 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2746 * Encode the stat struct into an ASCII representation.
2748 encode_stat(attribs, &st, sizeof(st), 0, stream);
2749 cnt = bsnprintf(buffer, sizeof(buffer),
2751 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2754 * Open the extended or extensible attribute file.
2756 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2759 retval = bxattr_exit_ok;
2763 _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2764 target_attrname, jcr->last_fname, be.bstrerror());
2765 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2766 target_attrname, jcr->last_fname, be.bstrerror());
2773 * The current implementation of xattr on Solaris doesn't support this, but if it
2774 * ever does we are prepared.
2775 * Encode the stat struct into an ASCII representation.
2777 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2780 retval = bxattr_exit_ok;
2784 _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2785 target_attrname, jcr->last_fname, be.bstrerror());
2786 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2787 target_attrname, jcr->last_fname, be.bstrerror());
2793 * Generate a xattr encoding with the reference to the target in there.
2795 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2796 cnt = bsnprintf(buffer, sizeof(buffer),
2798 target_attrname, 0, attribs, 0, link_source, 0);
2799 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2800 jcr->xattr_data->u.build->content_length = cnt;
2801 retval = send_xattr_stream(jcr, stream);
2803 if (retval == bxattr_exit_ok) {
2804 jcr->xattr_data->u.build->nr_saved++;
2808 * For a soft linked file we are ready now, no need to recursively save the attributes.
2816 * See if this is the first real xattr being saved.
2817 * If it is save the toplevel_hidden_dir attributes first.
2818 * This is easy as its stored already in the
2819 * jcr->xattr_data->u.build->content buffer.
2821 if (jcr->xattr_data->u.build->nr_saved == 0) {
2822 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2823 if (retval != bxattr_exit_ok) {
2826 jcr->xattr_data->u.build->nr_saved++;
2829 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2830 jcr->xattr_data->u.build->content_length = cnt;
2833 * Only dump the content of regular files.
2835 switch (st.st_mode & S_IFMT) {
2837 if (st.st_size > 0) {
2839 * Protect ourself against things getting out of hand.
2841 if (st.st_size >= MAX_XATTR_STREAM) {
2843 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2844 jcr->last_fname, MAX_XATTR_STREAM);
2848 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2849 jcr->xattr_data->u.build->content =
2850 check_pool_memory_size(jcr->xattr_data->u.build->content,
2851 jcr->xattr_data->u.build->content_length + cnt);
2852 memcpy(jcr->xattr_data->u.build->content +
2853 jcr->xattr_data->u.build->content_length, buffer, cnt);
2854 jcr->xattr_data->u.build->content_length += cnt;
2859 _("Unable to read content of xattr %s on file \"%s\"\n"),
2860 target_attrname, jcr->last_fname);
2861 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2862 target_attrname, jcr->last_fname);
2873 * We build a new xattr stream send it to the SD.
2875 retval = send_xattr_stream(jcr, stream);
2876 if (retval != bxattr_exit_ok) {
2879 jcr->xattr_data->u.build->nr_saved++;
2882 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2883 * available on this extended attribute.
2885 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2888 * The recursive call could change our working dir so change back to the wanted workdir.
2890 if (fchdir(fd) < 0) {
2893 retval = bxattr_exit_ok;
2897 _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2898 jcr->last_fname, be.bstrerror());
2899 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2900 jcr->last_fname, fd, be.bstrerror());
2906 if (acl_text != NULL) {
2915 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2918 int fd, filefd = -1, attrdirfd = -1;
2921 char current_xattr_namespace[PATH_MAX];
2922 bxattr_exit_code retval = bxattr_exit_error;
2926 * Determine what argument to use. Use attr_parent when set
2927 * (recursive call) or jcr->last_fname for first call. Also save
2928 * the current depth of the xattr_space we are in.
2932 if (xattr_namespace) {
2933 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2934 xattr_namespace, attr_parent);
2936 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2939 name = jcr->last_fname;
2940 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2944 * Open the file on which to save the xattrs read-only.
2946 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2949 retval = bxattr_exit_ok;
2953 _("Unable to open file \"%s\": ERR=%s\n"),
2954 jcr->last_fname, be.bstrerror());
2955 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2956 jcr->last_fname, be.bstrerror());
2962 * Open the xattr naming space.
2964 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2968 * Gentile way of the system saying this type of xattr layering is not supported.
2969 * Which is not problem we just forget about this this xattr.
2970 * But as this is not an error we return a positive return value.
2972 retval = bxattr_exit_ok;
2975 retval = bxattr_exit_ok;
2979 _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2980 name, jcr->last_fname, be.bstrerror());
2981 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2982 name, jcr->last_fname, be.bstrerror());
2988 * We need to change into the attribute directory to determine if each of the
2989 * attributes should be saved.
2991 if (fchdir(attrdirfd) < 0) {
2993 _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2994 jcr->last_fname, be.bstrerror());
2995 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2996 jcr->last_fname, attrdirfd, be.bstrerror());
3001 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
3002 * else because the readdir returns "." entry after the extensible attr entry.
3003 * And as we want this entry before anything else we better just save its data.
3006 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
3007 true, STREAM_XATTR_SOLARIS);
3009 if ((fd = dup(attrdirfd)) == -1 ||
3010 (dirp = fdopendir(fd)) == (DIR *)NULL) {
3012 _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
3013 jcr->last_fname, be.bstrerror());
3014 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
3015 jcr->last_fname, fd, be.bstrerror());
3021 * Walk the namespace.
3023 while ((dp = readdir(dirp)) != NULL) {
3025 * Skip only the toplevel . dir.
3027 if (!attr_parent && bstrcmp(dp->d_name, "."))
3031 * Skip all .. directories
3033 if (bstrcmp(dp->d_name, ".."))
3036 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
3037 current_xattr_namespace, dp->d_name, jcr->last_fname);
3039 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3041 * We are not interested in read-only extensible attributes.
3043 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
3044 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
3045 current_xattr_namespace, dp->d_name, jcr->last_fname);
3051 * We are only interested in read-write extensible attributes
3052 * when they contain non-transient values.
3054 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
3056 * Determine if there are non-transient system attributes at the toplevel.
3057 * We need to provide a fd to the open file.
3059 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
3060 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
3061 current_xattr_namespace, dp->d_name, jcr->last_fname);
3068 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3069 false, STREAM_XATTR_SOLARIS_SYS);
3072 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
3077 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3078 false, STREAM_XATTR_SOLARIS);
3082 retval = bxattr_exit_ok;
3085 if (attrdirfd != -1)
3093 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr,
3095 const char *attrname,
3098 #ifdef HAVE_EXTENDED_ACL
3103 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
3105 _("Unable to convert acl from text on file \"%s\"\n"),
3107 return bxattr_exit_error;
3110 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
3111 acl_set(attrname, aclp) != 0) {
3113 _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3114 attrname, jcr->last_fname, be.bstrerror());
3115 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3116 attrname, jcr->last_fname, be.bstrerror());
3117 return bxattr_exit_error;
3123 return bxattr_exit_ok;
3125 #else /* HAVE_EXTENDED_ACL */
3127 aclent_t *acls = NULL;
3130 acls = aclfromtext(acl_text, &n);
3132 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
3133 acl(attrname, SETACL, n, acls) != 0) {
3135 _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3136 attrname, jcr->last_fname, be.bstrerror());
3137 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3138 attrname, jcr->last_fname, be.bstrerror());
3139 return bxattr_exit_error;
3146 return bxattr_exit_ok;
3148 #endif /* HAVE_EXTENDED_ACL */
3151 #endif /* HAVE_ACL */
3153 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr,
3156 uint32_t content_length)
3159 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
3160 int used_bytes, cnt;
3161 char *bp, *target_attrname, *attribs;
3162 char *linked_target = NULL;
3163 char *acl_text = NULL;
3167 struct timeval times[2];
3168 bxattr_exit_code retval = bxattr_exit_error;
3172 * Parse the xattr stream. First the part that is the same for all xattrs.
3177 * The name of the target xattr has a leading / we are not interested
3178 * in that so skip it when decoding the string. We always start a the /
3179 * of the xattr space anyway.
3181 target_attrname = content + 1;
3182 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
3183 (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3189 * Open the file on which to restore the xattrs read-only.
3191 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
3193 _("Unable to open file \"%s\": ERR=%s\n"),
3194 jcr->last_fname, be.bstrerror());
3195 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
3196 jcr->last_fname, be.bstrerror());
3201 * Open the xattr naming space and make it the current working dir.
3203 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3205 _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
3206 jcr->last_fname, be.bstrerror());
3207 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
3208 jcr->last_fname, be.bstrerror());
3212 if (fchdir(attrdirfd) < 0) {
3214 _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3215 jcr->last_fname, be.bstrerror());
3216 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
3217 jcr->last_fname, attrdirfd, be.bstrerror());
3222 * Try to open the correct xattr subdir based on the target_attrname given.
3223 * e.g. check if its a subdir attrname. Each / in the string makes us go
3226 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
3229 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
3231 _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3232 target_attrname, jcr->last_fname, be.bstrerror());
3233 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3234 target_attrname, jcr->last_fname, be.bstrerror());
3242 * Open the xattr naming space.
3244 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3246 _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
3247 target_attrname, jcr->last_fname, be.bstrerror());
3248 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
3249 target_attrname, jcr->last_fname, be.bstrerror());
3257 * Make the xattr space our current workingdir.
3259 if (fchdir(attrdirfd) < 0) {
3261 _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
3262 target_attrname, jcr->last_fname, be.bstrerror());
3263 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
3264 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
3268 target_attrname = ++bp;
3272 * Decode the attributes from the stream.
3274 decode_stat(attribs, &st, sizeof(st), &inum);
3277 * Decode the next field (acl_text).
3279 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
3280 (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3286 * Based on the filetype perform the correct action. We support most filetypes here, more
3287 * then the actual implementation on Solaris supports so some code may never get executed
3288 * due to limitations in the implementation.
3290 switch (st.st_mode & S_IFMT) {
3293 * The current implementation of xattr on Solaris doesn't support this,
3294 * but if it ever does we are prepared.
3296 unlinkat(attrdirfd, target_attrname, 0);
3297 if (mkfifo(target_attrname, st.st_mode) < 0) {
3299 _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3300 target_attrname, jcr->last_fname, be.bstrerror());
3301 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
3302 target_attrname, jcr->last_fname, be.bstrerror());
3309 * The current implementation of xattr on Solaris doesn't support this,
3310 * but if it ever does we are prepared.
3312 unlinkat(attrdirfd, target_attrname, 0);
3313 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3315 _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3316 target_attrname, jcr->last_fname, be.bstrerror());
3317 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3318 target_attrname, jcr->last_fname, be.bstrerror());
3324 * If its not the hidden_dir create the entry.
3325 * The current implementation of xattr on Solaris doesn't support this,
3326 * but if it ever does we are prepared.
3328 if (!bstrcmp(target_attrname, ".")) {
3329 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3330 if (mkdir(target_attrname, st.st_mode) < 0) {
3331 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3332 target_attrname, jcr->last_fname, be.bstrerror());
3333 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3334 target_attrname, jcr->last_fname, be.bstrerror());
3341 * See if this is a hard linked file. e.g. inum != 0
3346 unlinkat(attrdirfd, target_attrname, 0);
3347 if (link(linked_target, target_attrname) < 0) {
3349 _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3350 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3351 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3352 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3357 * Successfully restored xattr.
3359 retval = bxattr_exit_ok;
3362 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3363 (used_bytes = (bp - content)) >= (int32_t)content_length) {
3367 if (used_bytes < (int32_t)(content_length - 1))
3371 * Restore the actual xattr.
3373 if (!is_extensible) {
3374 unlinkat(attrdirfd, target_attrname, 0);
3377 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3379 _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3380 target_attrname, jcr->last_fname, be.bstrerror());
3381 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3382 target_attrname, jcr->last_fname, be.bstrerror());
3388 * Restore the actual data.
3390 if (st.st_size > 0) {
3391 used_bytes = (data - content);
3392 cnt = content_length - used_bytes;
3395 * Do a sanity check, the st.st_size should be the same as the number of bytes
3396 * we have available as data of the stream.
3398 if (cnt != st.st_size) {
3400 _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3401 target_attrname, jcr->last_fname);
3402 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3403 target_attrname, jcr->last_fname);
3408 cnt = write(attrfd, data, cnt);
3411 _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3412 target_attrname, jcr->last_fname, be.bstrerror());
3413 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3414 target_attrname, jcr->last_fname, be.bstrerror());
3420 cnt = content_length - used_bytes;
3426 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3430 if (symlink(linked_target, target_attrname) < 0) {
3432 _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3433 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3434 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3435 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3440 * Successfully restored xattr.
3442 retval = bxattr_exit_ok;
3449 * Restore owner and acl for non extensible attributes.
3451 if (!is_extensible) {
3452 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3456 * Gentile way of the system saying this type of xattr layering is not supported.
3457 * But as this is not an error we return a positive return value.
3459 retval = bxattr_exit_ok;
3462 retval = bxattr_exit_ok;
3466 _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3467 target_attrname, jcr->last_fname, be.bstrerror());
3468 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3469 target_attrname, jcr->last_fname, be.bstrerror());
3476 if (acl_text && *acl_text)
3477 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3479 #endif /* HAVE_ACL */
3482 * For a non extensible attribute restore access and modification time on the xattr.
3484 if (!is_extensible) {
3485 times[0].tv_sec = st.st_atime;
3486 times[0].tv_usec = 0;
3487 times[1].tv_sec = st.st_mtime;
3488 times[1].tv_usec = 0;
3490 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3492 _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3493 target_attrname, jcr->last_fname, be.bstrerror());
3494 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3495 target_attrname, jcr->last_fname, be.bstrerror());
3501 * Successfully restored xattr.
3503 retval = bxattr_exit_ok;
3508 _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3510 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3517 if (attrdirfd != -1) {
3526 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3529 bxattr_exit_code retval = bxattr_exit_ok;
3532 * First see if extended attributes or extensible attributes are present.
3533 * If not just pretend things went ok.
3535 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3536 jcr->xattr_data->u.build->nr_saved = 0;
3539 * As we change the cwd in the save function save the current cwd
3540 * for restore after return from the solaris_save_xattrs function.
3542 getcwd(cwd, sizeof(cwd));
3543 retval = solaris_save_xattrs(jcr, NULL, NULL);
3545 if (jcr->xattr_data->u.build->link_cache) {
3546 delete jcr->xattr_data->u.build->link_cache;
3547 jcr->xattr_data->u.build->link_cache = NULL;
3553 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr,
3556 uint32_t content_length)
3559 bool is_extensible = false;
3560 bxattr_exit_code retval;
3563 * First make sure we can restore xattr on the filesystem.
3566 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3567 case STREAM_XATTR_SOLARIS_SYS:
3568 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3570 _("Failed to restore extensible attributes on file \"%s\"\n"),
3572 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3574 return bxattr_exit_error;
3577 is_extensible = true;
3580 case STREAM_XATTR_SOLARIS:
3581 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3583 _("Failed to restore extended attributes on file \"%s\"\n"),
3585 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3587 return bxattr_exit_error;
3591 return bxattr_exit_error;
3595 * As we change the cwd in the restore function save the current cwd
3596 * for restore after return from the solaris_restore_xattrs function.
3598 getcwd(cwd, sizeof(cwd));
3599 retval = solaris_restore_xattrs(jcr, is_extensible, content, content_length);
3606 * Function pointers to the build and parse function to use for these xattrs.
3608 static bxattr_exit_code (*os_build_xattr_streams)
3609 (JCR *jcr, FF_PKT *ff_pkt) =
3610 solaris_build_xattr_streams;
3611 static bxattr_exit_code (*os_parse_xattr_streams)
3612 (JCR *jcr, int stream, char *content, uint32_t content_length) =
3613 solaris_parse_xattr_streams;
3615 #endif /* defined(HAVE_SUN_OS) */
3618 * Entry points when compiled with support for XATTRs on a supported platform.
3620 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3623 * See if we are changing from one device to an other.
3624 * We save the current device we are scanning and compare
3625 * it with the current st_dev in the last stat performed on
3626 * the file we are currently storing.
3628 if (jcr->xattr_data->current_dev != ff_pkt->statp.st_dev) {
3630 * Reset the acl save flags.
3632 jcr->xattr_data->flags = 0;
3633 jcr->xattr_data->flags |= BXATTR_FLAG_SAVE_NATIVE;
3636 * Save that we started scanning a new filesystem.
3638 jcr->xattr_data->current_dev = ff_pkt->statp.st_dev;
3641 if ((jcr->xattr_data->flags & BXATTR_FLAG_SAVE_NATIVE) && os_parse_xattr_streams) {
3642 return os_build_xattr_streams(jcr, ff_pkt);
3644 return bxattr_exit_ok;
3648 bxattr_exit_code parse_xattr_streams(JCR *jcr,
3651 uint32_t content_length)
3659 * See if we are changing from one device to an other.
3660 * We save the current device we are restoring to and compare
3661 * it with the current st_dev in the last stat performed on
3662 * the file we are currently restoring.
3664 ret = lstat(jcr->last_fname, &st);
3669 return bxattr_exit_ok;
3672 _("Unable to stat file \"%s\": ERR=%s\n"),
3673 jcr->last_fname, be.bstrerror());
3674 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
3675 jcr->last_fname, be.bstrerror());
3676 return bxattr_exit_error;
3682 if (jcr->xattr_data->current_dev != st.st_dev) {
3684 * Reset the acl save flags.
3686 jcr->xattr_data->flags = 0;
3687 jcr->xattr_data->flags |= BXATTR_FLAG_RESTORE_NATIVE;
3690 * Save that we started restoring to a new filesystem.
3692 jcr->xattr_data->current_dev = st.st_dev;
3696 * See if we are still restoring native xattr to this filesystem.
3698 if ((jcr->xattr_data->flags & BXATTR_FLAG_RESTORE_NATIVE) && os_parse_xattr_streams) {
3700 * See if we can parse this stream, and ifso give it a try.
3702 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3703 if (os_default_xattr_streams[cnt] == stream) {
3704 return os_parse_xattr_streams(jcr, stream, content, content_length);
3709 * Increment error count but don't log an error again for the same filesystem.
3711 jcr->xattr_data->u.parse->nr_errors++;
3712 return bxattr_exit_ok;
3716 * Issue a warning and discard the message. But pretend the restore was ok.
3718 Jmsg2(jcr, M_WARNING, 0,
3719 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3720 jcr->last_fname, stream);
3721 return bxattr_exit_error;