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;
355 * First get the length of the available list with extended attributes.
357 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
358 switch (xattr_list_len) {
365 return bxattr_exit_ok;
368 * If the filesystem reports it doesn't support XATTRs we clear the
369 * BXATTR_FLAG_SAVE_NATIVE flag so we skip XATTR saves on all other files
370 * on the same filesystem. The BXATTR_FLAG_SAVE_NATIVE flags gets sets again
371 * when we change from one filesystem to an other.
373 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
374 return bxattr_exit_ok;
377 _("llistea error on file \"%s\": ERR=%s\n"),
378 jcr->last_fname, be.bstrerror());
379 Dmsg2(100, "llistea error file=%s ERR=%s\n",
380 jcr->last_fname, be.bstrerror());
381 return bxattr_exit_error;
386 return bxattr_exit_ok;
392 * Allocate room for the extented attribute list.
394 xattr_list = (char *)malloc(xattr_list_len + 1);
395 memset(xattr_list, 0, xattr_list_len + 1);
398 * Get the actual list of extended attributes names for a file.
400 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
401 switch (xattr_list_len) {
408 retval = bxattr_exit_ok;
412 _("llistea error on file \"%s\": ERR=%s\n"),
413 jcr->last_fname, be.bstrerror());
414 Dmsg2(100, "llistea error file=%s ERR=%s\n",
415 jcr->last_fname, be.bstrerror());
423 xattr_list[xattr_list_len] = '\0';
426 * Walk the list of extended attributes names and retrieve the data.
427 * We already count the bytes needed for serializing the stream later on.
430 while ((bp - xattr_list) + 1 < xattr_list_len) {
434 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
440 name_length = strlen(bp);
441 if (skip_xattr || name_length == 0) {
442 Dmsg1(100, "Skipping xattr named %s\n", bp);
443 bp = strchr(bp, '\0') + 1;
448 * Each xattr valuepair starts with a magic so we can parse it easier.
450 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
451 current_xattr->magic = XATTR_MAGIC;
452 expected_serialize_len += sizeof(current_xattr->magic);
455 * Allocate space for storing the name.
457 current_xattr->name_length = name_length;
458 current_xattr->name = (char *)malloc(current_xattr->name_length);
459 memcpy(current_xattr->name, bp, current_xattr->name_length);
461 expected_serialize_len += sizeof(current_xattr->name_length) +
462 current_xattr->name_length;
465 * First see how long the value is for the extended attribute.
467 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
468 switch (xattr_value_len) {
475 retval = bxattr_exit_ok;
479 _("lgetea error on file \"%s\": ERR=%s\n"),
480 jcr->last_fname, be.bstrerror());
481 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
482 jcr->last_fname, be.bstrerror());
488 current_xattr->value = NULL;
489 current_xattr->value_length = 0;
490 expected_serialize_len += sizeof(current_xattr->value_length);
494 * Allocate space for storing the value.
496 current_xattr->value = (char *)malloc(xattr_value_len);
497 memset(current_xattr->value, 0, xattr_value_len);
499 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
500 if (xattr_value_len < 0) {
506 retval = bxattr_exit_ok;
510 _("lgetea error on file \"%s\": ERR=%s\n"),
511 jcr->last_fname, be.bstrerror());
512 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
513 jcr->last_fname, be.bstrerror());
518 * Store the actual length of the value.
520 current_xattr->value_length = xattr_value_len;
521 expected_serialize_len += sizeof(current_xattr->value_length) +
522 current_xattr->value_length;
525 * Protect ourself against things getting out of hand.
527 if (expected_serialize_len >= MAX_XATTR_STREAM) {
529 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
530 jcr->last_fname, MAX_XATTR_STREAM);
536 if (xattr_value_list == NULL) {
537 xattr_value_list = New(alist(10, not_owned_by_alist));
540 xattr_value_list->append(current_xattr);
541 current_xattr = NULL;
543 bp = strchr(bp, '\0') + 1;
547 xattr_list = (char *)NULL;
550 * If we found any xattr send them to the SD.
552 if (xattr_count > 0) {
554 * Serialize the datastream.
556 if (serialize_xattr_stream(jcr,
557 expected_serialize_len,
558 xattr_value_list) < expected_serialize_len) {
560 _("Failed to serialize extended attributes on file \"%s\"\n"),
562 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
568 * Send the datastream to the SD.
570 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
572 retval = bxattr_exit_ok;
576 if (current_xattr != NULL) {
577 if (current_xattr->value != NULL) {
578 free(current_xattr->value);
580 if (current_xattr->name != NULL) {
581 free(current_xattr->name);
585 if (xattr_list != NULL) {
588 if (xattr_value_list != NULL) {
589 xattr_drop_internal_table(xattr_value_list);
594 static bxattr_exit_code aix_parse_xattr_streams(JCR *jcr,
597 uint32_t content_length)
599 xattr_t *current_xattr;
600 alist *xattr_value_list;
602 xattr_value_list = New(alist(10, not_owned_by_alist));
604 if (unserialize_xattr_stream(jcr,
607 xattr_value_list) != bxattr_exit_ok) {
608 xattr_drop_internal_table(xattr_value_list);
609 return bxattr_exit_error;
612 foreach_alist(current_xattr, xattr_value_list) {
613 if (lsetea(jcr->last_fname,
615 current_xattr->value,
616 current_xattr->value_length, 0) != 0) {
625 * If the filesystem reports it doesn't support XATTRs we clear
626 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
627 * on all other files on the same filesystem. The
628 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
629 * change from one filesystem to an other.
631 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
635 _("lsetea error on file \"%s\": ERR=%s\n"),
636 jcr->last_fname, be.bstrerror());
637 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
638 jcr->last_fname, be.bstrerror());
644 xattr_drop_internal_table(xattr_value_list);
645 return bxattr_exit_ok;
648 xattr_drop_internal_table(xattr_value_list);
649 return bxattr_exit_error;
653 * Function pointers to the build and parse function to use for these xattrs.
655 static bxattr_exit_code (*os_build_xattr_streams)
656 (JCR *jcr, FF_PKT *ff_pkt) =
657 aix_xattr_build_streams;
658 static bxattr_exit_code (*os_parse_xattr_streams)
659 (JCR *jcr, int stream, char *content, uint32_t content_length) =
660 aix_parse_xattr_streams;
662 #elif defined(HAVE_IRIX_OS)
664 #include <sys/attributes.h>
667 * Define the supported XATTR streams for this OS
669 static int os_default_xattr_streams[1] = {
672 static const char *xattr_acl_skiplist[1] = {
675 static const char *xattr_skiplist[1] = {
679 struct xattr_naming_space {
684 static xattr_naming_space xattr_naming_spaces[] = {
690 ATTR_ROOT | ATTR_DONTFOLLOW
697 static bxattr_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
699 int cnt, length, xattr_count = 0;
700 attrlist_cursor_t cursor;
701 attrlist_t *attrlist;
702 attrlist_ent_t *attrlist_ent;
703 xattr_t *current_xattr = NULL;
704 alist *xattr_value_list = NULL;
705 uint32_t expected_serialize_len = 0;
706 bxattr_exit_code retval = bxattr_exit_error;
707 POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
709 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
710 memset(&cursor, 0, sizeof(attrlist_cursor_t));
712 if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
713 xattr_naming_spaces[cnt].flags, &cursor) != 0) {
718 retval = bxattr_exit_ok;
722 _("attr_list error on file \"%s\": ERR=%s\n"),
723 jcr->last_fname, be.bstrerror());
724 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
725 jcr->last_fname, be.bstrerror());
730 attrlist = (attrlist_t *)xattrbuf;
733 * Walk the available attributes.
735 for (cnt = 0; cnt < attrlist->al_count; cnt++) {
736 attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
739 * Each xattr valuepair starts with a magic so we can parse it easier.
741 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
742 current_xattr->magic = XATTR_MAGIC;
743 expected_serialize_len += sizeof(current_xattr->magic);
746 * Allocate space for storing the name.
747 * We store the name as <naming_space_name><xattr_name>
749 current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) +
750 strlen(attrlist_ent->a_name) + 1;
751 current_xattr->name = (char *)malloc(current_xattr->name_length);
752 bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
753 xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
755 expected_serialize_len += sizeof(current_xattr->name_length) +
756 current_xattr->name_length;
758 current_xattr->value_length = attrlist_ent->a_valuelen;
759 current_xattr->value = (char *)malloc(current_xattr->value_length);
762 * Retrieve the actual value of the xattr.
764 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
765 &length, xattr_naming_spaces[cnt].flags) != 0) {
771 retval = bxattr_exit_ok;
775 * The buffer for the xattr isn't big enough. the value of
776 * current_xattr->value_length is updated with the actual size
777 * of the xattr. So we free the old buffer and create a new one
780 free(current_xattr->value);
781 current_xattr->value = (char *)malloc(current_xattr->value_length);
782 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
783 &length, xattr_naming_spaces[cnt].flags) != 0) {
787 retval = bxattr_exit_ok;
791 _("attr_list error on file \"%s\": ERR=%s\n"),
792 jcr->last_fname, be.bstrerror(errno));
793 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
794 jcr->last_fname, be.bstrerror());
798 current_xattr->value_length = length;
803 _("attr_list error on file \"%s\": ERR=%s\n"),
804 jcr->last_fname, be.bstrerror());
805 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
806 jcr->last_fname, be.bstrerror());
810 current_xattr->value_length = length;
813 expected_serialize_len += sizeof(current_xattr->value_length) +
814 current_xattr->value_length;
817 * Protect ourself against things getting out of hand.
819 if (expected_serialize_len >= MAX_XATTR_STREAM) {
821 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
822 jcr->last_fname, MAX_XATTR_STREAM);
826 if (xattr_value_list == NULL) {
827 xattr_value_list = New(alist(10, not_owned_by_alist));
830 xattr_value_list->append(current_xattr);
831 current_xattr = NULL;
836 * See if there are more attributes available for a next run of attr_list.
838 if (attrlist->al_more == 0) {
845 * If we found any xattr send them to the SD.
847 if (xattr_count > 0) {
849 * Serialize the datastream.
851 if (serialize_xattr_stream(jcr,
852 expected_serialize_len,
853 xattr_value_list) < expected_serialize_len) {
855 _("Failed to serialize extended attributes on file \"%s\"\n"),
857 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
863 * Send the datastream to the SD.
865 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
867 retval = bxattr_exit_ok;
871 if (current_xattr != NULL) {
872 if (current_xattr->value != NULL) {
873 free(current_xattr->value);
875 if (current_xattr->name != NULL) {
876 free(current_xattr->name);
880 free_pool_memory(xattrbuf);
882 if (xattr_value_list != NULL) {
883 xattr_drop_internal_table(xattr_value_list);
888 static bxattr_exit_code irix_parse_xattr_streams(JCR *jcr,
891 uint32_t content_length)
894 int cnt, cmp_size, name_space_index, flags;
895 xattr_t *current_xattr;
896 alist *xattr_value_list;
897 bxattr_exit_code retval = bxattr_exit_error;
899 xattr_value_list = New(alist(10, not_owned_by_alist));
901 if (unserialize_xattr_stream(jcr,
904 xattr_value_list) != bxattr_exit_ok) {
905 xattr_drop_internal_table(xattr_value_list);
906 return bxattr_exit_error;
909 foreach_alist(current_xattr, xattr_value_list) {
911 * See to what namingspace this xattr belongs to.
913 name_space_index = 0;
914 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
915 cmp_size = strlen(xattr_naming_spaces[cnt].name);
916 if (!strncasecmp(current_xattr->name,
917 xattr_naming_spaces[cnt].name,
919 name_space_index = cnt;
925 * If we got a xattr that doesn't belong to an valid namespace complain.
927 if (name_space_index == 0) {
929 _("Received illegal xattr named %s on file \"%s\"\n"),
930 current_xattr->name, jcr->last_fname);
931 Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
932 current_xattr->name, jcr->last_fname);
937 * Restore the xattr first try to create the attribute from scratch.
939 flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
940 bp = strchr(current_xattr->name, '.');
941 if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
942 current_xattr->value_length, flags) != 0) {
947 retval = bxattr_exit_ok;
951 * The xattr already exists we need to replace it.
953 flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
954 if (attr_set(jcr->last_fname, bp, current_xattr->value,
955 current_xattr->value_length, flags) != 0) {
958 retval = bxattr_exit_ok;
962 _("attr_set error on file \"%s\": ERR=%s\n"),
963 jcr->last_fname, be.bstrerror(errno));
964 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
965 jcr->last_fname, be.bstrerror());
972 _("attr_set error on file \"%s\": ERR=%s\n"),
973 jcr->last_fname, be.bstrerror());
974 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
975 jcr->last_fname, be.bstrerror());
981 xattr_drop_internal_table(xattr_value_list);
982 return bxattr_exit_ok;
985 xattr_drop_internal_table(xattr_value_list);
986 return bxattr_exit_error;
990 * Function pointers to the build and parse function to use for these xattrs.
992 static bxattr_exit_code (*os_build_xattr_streams)
993 (JCR *jcr, FF_PKT *ff_pkt) =
994 irix_xattr_build_streams;
995 static bxattr_exit_code (*os_parse_xattr_streams)
996 (JCR *jcr, int stream, char *content, uint32_t content_length) =
997 irix_parse_xattr_streams;
999 #elif defined(HAVE_DARWIN_OS) || \
1000 defined(HAVE_LINUX_OS)
1002 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
1003 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
1004 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
1005 #error "Missing full support for the XATTR functions."
1008 #ifdef HAVE_SYS_XATTR_H
1009 #include <sys/xattr.h>
1011 #error "Missing sys/xattr.h header file"
1015 * Define the supported XATTR streams for this OS
1017 #if defined(HAVE_DARWIN_OS)
1018 static int os_default_xattr_streams[1] = {
1021 static const char *xattr_acl_skiplist[2] = {
1022 "com.apple.system.Security",
1025 static const char *xattr_skiplist[3] = {
1026 "com.apple.system.extendedsecurity",
1027 "com.apple.ResourceFork",
1030 #elif defined(HAVE_LINUX_OS)
1031 static int os_default_xattr_streams[1] = {
1034 static const char *xattr_acl_skiplist[3] = {
1035 "system.posix_acl_access",
1036 "system.posix_acl_default",
1039 static const char *xattr_skiplist[1] = {
1045 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
1046 * listxattr, getxattr and setxattr with an extra options argument
1047 * which mimics the l variants of the functions when we specify
1048 * XATTR_NOFOLLOW as the options value.
1050 #if defined(HAVE_DARWIN_OS)
1051 #define llistxattr(path, list, size) \
1052 listxattr((path), (list), (size), XATTR_NOFOLLOW)
1053 #define lgetxattr(path, name, value, size) \
1054 getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
1055 #define lsetxattr(path, name, value, size, flags) \
1056 setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
1059 * Fallback to the non l-functions when those are not available.
1061 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
1062 #define lgetxattr getxattr
1064 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
1065 #define lsetxattr setxattr
1067 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
1068 #define llistxattr listxattr
1072 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
1075 char *xattr_list, *bp;
1076 int cnt, xattr_count = 0;
1077 uint32_t name_length;
1078 int32_t xattr_list_len,
1080 uint32_t expected_serialize_len = 0;
1081 xattr_t *current_xattr = NULL;
1082 alist *xattr_value_list = NULL;
1083 bxattr_exit_code retval = bxattr_exit_error;
1086 * First get the length of the available list with extended attributes.
1088 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
1089 switch (xattr_list_len) {
1095 return bxattr_exit_ok;
1096 case BXATTR_ENOTSUP:
1098 * If the filesystem reports it doesn't support XATTRs we clear
1099 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1100 * on all other files on the same filesystem. The
1101 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1102 * change from one filesystem to an other.
1104 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1105 return bxattr_exit_ok;
1108 _("llistxattr error on file \"%s\": ERR=%s\n"),
1109 jcr->last_fname, be.bstrerror());
1110 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1111 jcr->last_fname, be.bstrerror());
1112 return bxattr_exit_error;
1117 return bxattr_exit_ok;
1123 * Allocate room for the extented attribute list.
1125 xattr_list = (char *)malloc(xattr_list_len + 1);
1126 memset(xattr_list, 0, xattr_list_len + 1);
1129 * Get the actual list of extended attributes names for a file.
1131 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
1132 switch (xattr_list_len) {
1138 retval = bxattr_exit_ok;
1142 _("llistxattr error on file \"%s\": ERR=%s\n"),
1143 jcr->last_fname, be.bstrerror());
1144 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1145 jcr->last_fname, be.bstrerror());
1153 xattr_list[xattr_list_len] = '\0';
1156 * Walk the list of extended attributes names and retrieve the data.
1157 * We already count the bytes needed for serializing the stream later on.
1160 while ((bp - xattr_list) + 1 < xattr_list_len) {
1164 * On some OSes you also get the acls in the extented attribute list.
1165 * So we check if we are already backing up acls and if we do we
1166 * don't store the extended attribute with the same info.
1168 if (ff_pkt->flags & FO_ACL) {
1169 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1170 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1178 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1181 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1182 if (bstrcmp(bp, xattr_skiplist[cnt])) {
1189 name_length = strlen(bp);
1190 if (skip_xattr || name_length == 0) {
1191 Dmsg1(100, "Skipping xattr named %s\n", bp);
1192 bp = strchr(bp, '\0') + 1;
1197 * Each xattr valuepair starts with a magic so we can parse it easier.
1199 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1200 current_xattr->magic = XATTR_MAGIC;
1201 expected_serialize_len += sizeof(current_xattr->magic);
1204 * Allocate space for storing the name.
1206 current_xattr->name_length = name_length;
1207 current_xattr->name = (char *)malloc(current_xattr->name_length);
1208 memcpy(current_xattr->name, bp, current_xattr->name_length);
1210 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1213 * First see how long the value is for the extended attribute.
1215 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1216 switch (xattr_value_len) {
1222 retval = bxattr_exit_ok;
1226 _("lgetxattr error on file \"%s\": ERR=%s\n"),
1227 jcr->last_fname, be.bstrerror());
1228 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1229 jcr->last_fname, be.bstrerror());
1235 current_xattr->value = NULL;
1236 current_xattr->value_length = 0;
1237 expected_serialize_len += sizeof(current_xattr->value_length);
1241 * Allocate space for storing the value.
1243 current_xattr->value = (char *)malloc(xattr_value_len);
1244 memset(current_xattr->value, 0, xattr_value_len);
1246 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1247 if (xattr_value_len < 0) {
1252 retval = bxattr_exit_ok;
1256 _("lgetxattr error on file \"%s\": ERR=%s\n"),
1257 jcr->last_fname, be.bstrerror());
1258 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1259 jcr->last_fname, be.bstrerror());
1264 * Store the actual length of the value.
1266 current_xattr->value_length = xattr_value_len;
1267 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1270 * Protect ourself against things getting out of hand.
1272 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1274 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1275 jcr->last_fname, MAX_XATTR_STREAM);
1280 if (xattr_value_list == NULL) {
1281 xattr_value_list = New(alist(10, not_owned_by_alist));
1284 xattr_value_list->append(current_xattr);
1285 current_xattr = NULL;
1287 bp = strchr(bp, '\0') + 1;
1292 xattr_list = (char *)NULL;
1295 * If we found any xattr send them to the SD.
1297 if (xattr_count > 0) {
1299 * Serialize the datastream.
1301 if (serialize_xattr_stream(jcr,
1302 expected_serialize_len,
1303 xattr_value_list) < expected_serialize_len) {
1305 _("Failed to serialize extended attributes on file \"%s\"\n"),
1307 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1313 * Send the datastream to the SD.
1315 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1317 retval = bxattr_exit_ok;
1321 if (current_xattr != NULL) {
1322 if (current_xattr->value != NULL) {
1323 free(current_xattr->value);
1325 if (current_xattr->name != NULL) {
1326 free(current_xattr->name);
1328 free(current_xattr);
1330 if (xattr_list != NULL) {
1333 if (xattr_value_list != NULL) {
1334 xattr_drop_internal_table(xattr_value_list);
1339 static bxattr_exit_code generic_parse_xattr_streams(JCR *jcr,
1342 uint32_t content_length)
1344 xattr_t *current_xattr;
1345 alist *xattr_value_list;
1347 xattr_value_list = New(alist(10, not_owned_by_alist));
1349 if (unserialize_xattr_stream(jcr,
1352 xattr_value_list) != bxattr_exit_ok) {
1353 xattr_drop_internal_table(xattr_value_list);
1354 return bxattr_exit_error;
1357 foreach_alist(current_xattr, xattr_value_list) {
1358 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1364 case BXATTR_ENOTSUP:
1366 * If the filesystem reports it doesn't support XATTRs we clear
1367 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1368 * on all other files on the same filesystem. The
1369 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1370 * change from one filesystem to an other.
1372 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
1376 _("lsetxattr error on file \"%s\": ERR=%s\n"),
1377 jcr->last_fname, be.bstrerror());
1378 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1379 jcr->last_fname, be.bstrerror());
1385 xattr_drop_internal_table(xattr_value_list);
1386 return bxattr_exit_ok;
1389 xattr_drop_internal_table(xattr_value_list);
1390 return bxattr_exit_error;
1394 * Function pointers to the build and parse function to use for these xattrs.
1396 static bxattr_exit_code (*os_build_xattr_streams)
1397 (JCR *jcr, FF_PKT *ff_pkt) =
1398 generic_xattr_build_streams;
1399 static bxattr_exit_code (*os_parse_xattr_streams)
1400 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1401 generic_parse_xattr_streams;
1403 #elif defined(HAVE_FREEBSD_OS) || \
1404 defined(HAVE_NETBSD_OS) || \
1405 defined(HAVE_OPENBSD_OS)
1407 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1408 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1409 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1410 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1411 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1412 #error "Missing full support for the extattr functions."
1415 #ifdef HAVE_SYS_EXTATTR_H
1416 #include <sys/extattr.h>
1418 #error "Missing sys/extattr.h header file"
1421 #ifdef HAVE_LIBUTIL_H
1422 #include <libutil.h>
1425 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1426 #define extattr_get_link extattr_get_file
1428 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1429 #define extattr_set_link extattr_set_file
1431 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1432 #define extattr_list_link extattr_list_file
1435 #if defined(HAVE_FREEBSD_OS)
1436 static int os_default_xattr_streams[1] = {
1437 STREAM_XATTR_FREEBSD
1439 static int os_default_xattr_namespaces[2] = {
1440 EXTATTR_NAMESPACE_USER,
1441 EXTATTR_NAMESPACE_SYSTEM
1443 static const char *xattr_acl_skiplist[4] = {
1444 "system.posix1e.acl_access",
1445 "system.posix1e.acl_default",
1449 static const char *xattr_skiplist[1] = {
1452 #elif defined(HAVE_NETBSD_OS)
1453 static int os_default_xattr_streams[1] = {
1456 static int os_default_xattr_namespaces[2] = {
1457 EXTATTR_NAMESPACE_USER,
1458 EXTATTR_NAMESPACE_SYSTEM
1460 static const char *xattr_acl_skiplist[1] = {
1463 static const char *xattr_skiplist[1] = {
1466 #elif defined(HAVE_OPENBSD_OS)
1467 static int os_default_xattr_streams[1] = {
1468 STREAM_XATTR_OPENBSD
1470 static int os_default_xattr_namespaces[2] = {
1471 EXTATTR_NAMESPACE_USER,
1472 EXTATTR_NAMESPACE_SYSTEM
1474 static const char *xattr_acl_skiplist[1] = {
1477 static const char *xattr_skiplist[1] = {
1482 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1486 int cnt, index, xattr_count = 0;
1487 int32_t xattr_list_len,
1489 uint32_t expected_serialize_len = 0;
1490 unsigned int namespace_index;
1492 char *current_attrnamespace = NULL;
1493 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1494 xattr_t *current_xattr = NULL;
1495 alist *xattr_value_list = NULL;
1496 bxattr_exit_code retval = bxattr_exit_error;
1499 * Loop over all available xattr namespaces.
1501 for (namespace_index = 0;
1502 namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int);
1503 namespace_index++) {
1504 attrnamespace = os_default_xattr_namespaces[namespace_index];
1507 * First get the length of the available list with extended attributes.
1508 * If we get EPERM on system namespace, don't return error.
1509 * This is expected for normal users trying to archive the system
1510 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1511 * they've decided to return EOPNOTSUPP instead.
1513 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1514 switch (xattr_list_len) {
1520 retval = bxattr_exit_ok;
1522 #if defined(EOPNOTSUPP)
1526 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1534 _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1535 jcr->last_fname, be.bstrerror());
1536 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1537 jcr->last_fname, be.bstrerror());
1549 * Allocate room for the extented attribute list.
1551 xattr_list = (char *)malloc(xattr_list_len + 1);
1552 memset(xattr_list, 0, xattr_list_len + 1);
1555 * Get the actual list of extended attributes names for a file.
1557 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace,
1558 xattr_list, xattr_list_len);
1559 switch (xattr_list_len) {
1565 retval = bxattr_exit_ok;
1569 _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1570 jcr->last_fname, be.bstrerror());
1571 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1572 jcr->last_fname, be.bstrerror());
1580 xattr_list[xattr_list_len] = '\0';
1583 * Convert the numeric attrnamespace into a string representation and make
1584 * a private copy of that string. The extattr_namespace_to_string functions
1585 * returns a strdupped string which we need to free.
1587 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1589 _("Failed to convert %d into namespace on file \"%s\"\n"),
1590 attrnamespace, jcr->last_fname);
1591 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1592 attrnamespace, jcr->last_fname);
1597 * Walk the list of extended attributes names and retrieve the data.
1598 * We already count the bytes needed for serializing the stream later on.
1600 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1604 * Print the current name into the buffer as its not null terminated
1605 * we need to use the length encoded in the string for copying only
1608 cnt = xattr_list[index];
1609 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1610 cnt = ((int)sizeof(current_attrname) - 1);
1612 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1613 current_attrname[cnt] = '\0';
1616 * First make a xattr tuple of the current namespace and the name of
1617 * the xattr. e.g. something like user.<attrname> or system.<attrname>
1619 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s",
1620 current_attrnamespace, current_attrname);
1623 * On some OSes you also get the acls in the extented attribute list.
1624 * So we check if we are already backing up acls and if we do we
1625 * don't store the extended attribute with the same info.
1627 if (ff_pkt->flags & FO_ACL) {
1628 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1629 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1637 * On some OSes we want to skip certain xattrs which are in the
1638 * xattr_skiplist array.
1641 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1642 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1650 Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1655 * Each xattr valuepair starts with a magic so we can parse it easier.
1657 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1658 current_xattr->magic = XATTR_MAGIC;
1659 expected_serialize_len += sizeof(current_xattr->magic);
1662 * Allocate space for storing the name.
1664 current_xattr->name_length = strlen(current_attrtuple);
1665 current_xattr->name = (char *)malloc(current_xattr->name_length);
1666 memcpy(current_xattr->name, current_attrtuple, current_xattr->name_length);
1668 expected_serialize_len += sizeof(current_xattr->name_length) +
1669 current_xattr->name_length;
1672 * First see how long the value is for the extended attribute.
1674 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1675 current_attrname, NULL, 0);
1676 switch (xattr_value_len) {
1682 retval = bxattr_exit_ok;
1686 _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1687 jcr->last_fname, be.bstrerror());
1688 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1689 jcr->last_fname, be.bstrerror());
1695 current_xattr->value = NULL;
1696 current_xattr->value_length = 0;
1697 expected_serialize_len += sizeof(current_xattr->value_length);
1701 * Allocate space for storing the value.
1703 current_xattr->value = (char *)malloc(xattr_value_len);
1704 memset(current_xattr->value, 0, xattr_value_len);
1706 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1707 current_attrname, current_xattr->value,
1709 if (xattr_value_len < 0) {
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());
1727 * Store the actual length of the value.
1729 current_xattr->value_length = xattr_value_len;
1730 expected_serialize_len += sizeof(current_xattr->value_length) +
1731 current_xattr->value_length;
1734 * Protect ourself against things getting out of hand.
1736 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1738 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1739 jcr->last_fname, MAX_XATTR_STREAM);
1745 if (xattr_value_list == NULL) {
1746 xattr_value_list = New(alist(10, not_owned_by_alist));
1749 xattr_value_list->append(current_xattr);
1750 current_xattr = NULL;
1756 * Drop the local copy of the current_attrnamespace.
1758 actuallyfree(current_attrnamespace);
1759 current_attrnamespace = NULL;
1762 * We are done with this xattr list.
1765 xattr_list = (char *)NULL;
1769 * If we found any xattr send them to the SD.
1771 if (xattr_count > 0) {
1773 * Serialize the datastream.
1775 if (serialize_xattr_stream(jcr,
1776 expected_serialize_len,
1777 xattr_value_list) < expected_serialize_len) {
1779 _("Failed to serialize extended attributes on file \"%s\"\n"),
1781 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1787 * Send the datastream to the SD.
1789 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1791 retval = bxattr_exit_ok;
1795 if (current_attrnamespace != NULL) {
1796 actuallyfree(current_attrnamespace);
1798 if (current_xattr != NULL) {
1799 if (current_xattr->value != NULL) {
1800 free(current_xattr->value);
1802 if (current_xattr->name != NULL) {
1803 free(current_xattr->name);
1805 free(current_xattr);
1807 if (xattr_list != NULL) {
1810 if (xattr_value_list != NULL) {
1811 xattr_drop_internal_table(xattr_value_list);
1816 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr,
1819 uint32_t content_length)
1821 xattr_t *current_xattr;
1822 alist *xattr_value_list;
1823 int current_attrnamespace, cnt;
1824 char *attrnamespace, *attrname;
1826 xattr_value_list = New(alist(10, not_owned_by_alist));
1828 if (unserialize_xattr_stream(jcr,
1831 xattr_value_list) != bxattr_exit_ok) {
1832 xattr_drop_internal_table(xattr_value_list);
1833 return bxattr_exit_error;
1836 foreach_alist(current_xattr, xattr_value_list) {
1838 * Try splitting the xattr_name into a namespace and name part.
1839 * The splitting character is a .
1841 attrnamespace = current_xattr->name;
1842 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1844 _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1845 current_xattr->name, jcr->last_fname);
1846 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1847 current_xattr->name, jcr->last_fname);
1853 * Make sure the attrnamespace makes sense.
1855 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1857 _("Failed to convert %s into namespace on file \"%s\"\n"),
1858 attrnamespace, jcr->last_fname);
1859 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1860 attrnamespace, jcr->last_fname);
1865 * Try restoring the extended attribute.
1867 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1868 attrname, current_xattr->value, current_xattr->value_length);
1869 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1878 _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1879 jcr->last_fname, be.bstrerror());
1880 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1881 jcr->last_fname, be.bstrerror());
1888 xattr_drop_internal_table(xattr_value_list);
1889 return bxattr_exit_ok;
1892 xattr_drop_internal_table(xattr_value_list);
1893 return bxattr_exit_error;
1897 * Function pointers to the build and parse function to use for these xattrs.
1899 static bxattr_exit_code (*os_build_xattr_streams)
1900 (JCR *jcr, FF_PKT *ff_pkt) =
1901 bsd_build_xattr_streams;
1902 static bxattr_exit_code (*os_parse_xattr_streams)
1903 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1904 bsd_parse_xattr_streams;
1906 #elif defined(HAVE_OSF1_OS)
1908 #if !defined(HAVE_GETPROPLIST) || \
1909 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1910 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1911 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1912 !defined(HAVE_SETPROPLIST)
1913 #error "Missing full support for the Extended Attributes functions."
1916 #ifdef HAVE_SYS_PROPLIST_H
1917 #include <sys/proplist.h>
1919 #error "Missing sys/proplist.h header file"
1923 * Define the supported XATTR streams for this OS
1925 static int os_default_xattr_streams[1] = {
1928 static const char *xattr_acl_skiplist[1] = {
1931 static const char *xattr_skiplist[1] = {
1935 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1942 int xattr_count = 0;
1945 int32_t xattr_list_len,
1948 uint32_t expected_serialize_len = 0;
1949 xattr_t *current_xattr = NULL;
1950 alist *xattr_value_list = NULL;
1951 struct proplistname_args prop_args;
1952 bxattr_exit_code retval = bxattr_exit_error;
1953 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1955 xattrbuf_size = sizeof_pool_memory(xattrbuf);
1956 xattrbuf_min_size = 0;
1957 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1958 xattrbuf, &xattrbuf_min_size);
1961 * See what xattr are available.
1963 switch (xattr_list_len) {
1970 * If the filesystem reports it doesn't support XATTRs we clear
1971 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1972 * on all other files on the same filesystem. The
1973 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1974 * change from one filesystem to an other.
1976 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1977 retval = bxattr_exit_ok;
1981 _("getproplist error on file \"%s\": ERR=%s\n"),
1982 jcr->last_fname, be.bstrerror());
1983 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1984 jcr->last_fname, be.bstrerror());
1990 if (xattrbuf_min_size) {
1992 * The buffer isn't big enough to hold the xattr data, we now have
1993 * a minimum buffersize so we resize the buffer and try again.
1995 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1996 xattrbuf_size = xattrbuf_min_size + 1;
1997 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1998 xattrbuf, &xattrbuf_min_size);
1999 switch (xattr_list_len) {
2006 _("getproplist error on file \"%s\": ERR=%s\n"),
2007 jcr->last_fname, be.bstrerror());
2008 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
2009 jcr->last_fname, be.bstrerror());
2016 * This should never happen as we sized the buffer according to the minimumsize
2017 * returned by a previous getproplist call. If it does happen things are fishy and
2018 * we are better of forgetting this xattr as it seems its list is changing at this
2019 * exact moment so we can never make a good backup copy of it.
2021 retval = bxattr_exit_ok;
2030 retval = bxattr_exit_ok;
2039 * Walk the list of extended attributes names and retrieve the data.
2040 * We already count the bytes needed for serializing the stream later on.
2043 while (xattrbuf_size > 0) {
2045 * Call getproplist_entry to initialize name and value
2046 * pointers to entries position within buffer.
2048 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
2051 * On some OSes you also get the acls in the extented attribute list.
2052 * So we check if we are already backing up acls and if we do we
2053 * don't store the extended attribute with the same info.
2055 if (ff_pkt->flags & FO_ACL) {
2056 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
2057 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
2065 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
2068 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
2069 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
2077 Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
2082 * Each xattr valuepair starts with a magic so we can parse it easier.
2084 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
2085 current_xattr->magic = XATTR_MAGIC;
2086 expected_serialize_len += sizeof(current_xattr->magic);
2088 current_xattr->name_length = strlen(xattr_name);
2089 current_xattr->name = bstrdup(xattr_name);
2091 expected_serialize_len += sizeof(current_xattr->name_length) +
2092 current_xattr->name_length;
2094 current_xattr->value_length = *xattr_value_len;
2095 current_xattr->value = (char *)malloc(current_xattr->value_length);
2096 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
2098 expected_serialize_len += sizeof(current_xattr->value_length) +
2099 current_xattr->value_length;
2102 * Protect ourself against things getting out of hand.
2104 if (expected_serialize_len >= MAX_XATTR_STREAM) {
2106 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2107 jcr->last_fname, MAX_XATTR_STREAM);
2111 if (xattr_value_list == NULL) {
2112 xattr_value_list = New(alist(10, not_owned_by_alist));
2115 xattr_value_list->append(current_xattr);
2116 current_xattr = NULL;
2121 * If we found any xattr send them to the SD.
2123 if (xattr_count > 0) {
2125 * Serialize the datastream.
2127 if (serialize_xattr_stream(jcr,
2128 expected_serialize_len,
2129 xattr_value_list) < expected_serialize_len) {
2131 _("Failed to serialize extended attributes on file \"%s\"\n"),
2133 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
2139 * Send the datastream to the SD.
2141 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
2143 retval = bxattr_exit_ok;
2147 if (current_xattr != NULL) {
2148 if (current_xattr->value != NULL) {
2149 free(current_xattr->value);
2151 if (current_xattr->name != NULL) {
2152 free(current_xattr->name);
2154 free(current_xattr);
2156 if (xattr_value_list != NULL) {
2157 xattr_drop_internal_table(xattr_value_list);
2159 free_pool_memory(xattrbuf);
2164 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr,
2167 uint32_t content_length)
2169 char *bp, *xattrbuf = NULL;
2170 int32_t xattrbuf_size, cnt;
2171 xattr_t *current_xattr;
2172 alist *xattr_value_list;
2173 bxattr_exit_code retval = bxattr_exit_error;
2175 xattr_value_list = New(alist(10, not_owned_by_alist));
2177 if (unserialize_xattr_stream(jcr,
2180 xattr_value_list) != bxattr_exit_ok) {
2181 xattr_drop_internal_table(xattr_value_list);
2182 return bxattr_exit_error;
2186 * See how big the propertylist must be.
2189 foreach_alist(current_xattr, xattr_value_list) {
2190 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
2193 xattrbuf = (char *)malloc(xattrbuf_size);
2196 * Add all value pairs to the proplist.
2200 foreach_alist(current_xattr, xattr_value_list) {
2201 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
2202 current_xattr->value, &bp);
2208 if (cnt != xattrbuf_size) {
2210 _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
2212 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
2218 * Restore the list of extended attributes on the file.
2220 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
2228 * If the filesystem reports it doesn't support XATTRs we clear
2229 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
2230 * on all other files on the same filesystem. The
2231 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
2232 * change from one filesystem to an other.
2234 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
2235 retval = bxattr_exit_ok;
2239 _("setproplist error on file \"%s\": ERR=%s\n"),
2240 jcr->last_fname, be.bstrerror());
2241 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
2242 jcr->last_fname, be.bstrerror());
2253 xattr_drop_internal_table(xattr_value_list);
2254 return bxattr_exit_ok;
2260 xattr_drop_internal_table(xattr_value_list);
2261 return bxattr_exit_error;
2265 * Function pointers to the build and parse function to use for these xattrs.
2267 static bxattr_exit_code (*os_build_xattr_streams)
2268 (JCR *jcr, FF_PKT *ff_pkt) =
2269 tru64_build_xattr_streams;
2270 static bxattr_exit_code (*os_parse_xattr_streams)
2271 (JCR *jcr, int stream, char *content, uint32_t content_length) =
2272 tru64_parse_xattr_streams;
2274 #elif defined(HAVE_SUN_OS)
2276 * Solaris extended attributes were introduced in Solaris 9
2279 * Solaris extensible attributes were introduced in OpenSolaris
2280 * by PSARC 2007/315 Solaris extensible attributes are also
2281 * sometimes called extended system attributes.
2283 * man fsattr(5) on Solaris gives a wealth of info. The most
2284 * important bits are:
2286 * Attributes are logically supported as files within the file
2287 * system. The file system is therefore augmented with an
2288 * orthogonal name space of file attributes. Any file (includ-
2289 * ing attribute files) can have an arbitrarily deep attribute
2290 * tree associated with it. Attribute values are accessed by
2291 * file descriptors obtained through a special attribute inter-
2292 * face. This logical view of "attributes as files" allows the
2293 * leveraging of existing file system interface functionality
2294 * to support the construction, deletion, and manipulation of
2297 * The special files "." and ".." retain their accustomed
2298 * semantics within the attribute hierarchy. The "." attribute
2299 * file refers to the current directory and the ".." attribute
2300 * file refers to the parent directory. The unnamed directory
2301 * at the head of each attribute tree is considered the "child"
2302 * of the file it is associated with and the ".." file refers
2303 * to the associated file. For any non-directory file with
2304 * attributes, the ".." entry in the unnamed directory refers
2305 * to a file that is not a directory.
2307 * Conceptually, the attribute model is fully general. Extended
2308 * attributes can be any type of file (doors, links, direc-
2309 * tories, and so forth) and can even have their own attributes
2310 * (fully recursive). As a result, the attributes associated
2311 * with a file could be an arbitrarily deep directory hierarchy
2312 * where each attribute could have an equally complex attribute
2313 * tree associated with it. Not all implementations are able
2314 * to, or want to, support the full model. Implementation are
2315 * therefore permitted to reject operations that are not sup-
2316 * ported. For example, the implementation for the UFS file
2317 * system allows only regular files as attributes (for example,
2318 * no sub-directories) and rejects attempts to place attributes
2321 * The following list details the operations that are rejected
2322 * in the current implementation:
2324 * link Any attempt to create links between
2325 * attribute and non-attribute space
2326 * is rejected to prevent security-
2327 * related or otherwise sensitive
2328 * attributes from being exposed, and
2329 * therefore manipulable, as regular
2332 * rename Any attempt to rename between
2333 * attribute and non-attribute space
2334 * is rejected to prevent an already
2335 * linked file from being renamed and
2336 * thereby circumventing the link res-
2339 * mkdir, symlink, mknod Any attempt to create a "non-
2340 * regular" file in attribute space is
2341 * rejected to reduce the functional-
2342 * ity, and therefore exposure and
2343 * risk, of the initial implementa-
2346 * The entire available name space has been allocated to "gen-
2347 * eral use" to bring the implementation in line with the NFSv4
2348 * draft standard [NFSv4]. That standard defines "named attri-
2349 * butes" (equivalent to Solaris Extended Attributes) with no
2350 * naming restrictions. All Sun applications making use of
2351 * opaque extended attributes will use the prefix "SUNW".
2354 #ifdef HAVE_SYS_ATTR_H
2355 #include <sys/attr.h>
2362 #ifdef HAVE_SYS_NVPAIR_H
2363 #include <sys/nvpair.h>
2366 #ifdef HAVE_SYS_ACL_H
2367 #include <sys/acl.h>
2370 #if !defined(HAVE_OPENAT) || \
2371 !defined(HAVE_UNLINKAT) || \
2372 !defined(HAVE_FCHOWNAT) || \
2373 !defined(HAVE_FUTIMESAT)
2374 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2378 * Define the supported XATTR streams for this OS
2380 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2381 static int os_default_xattr_streams[2] = {
2382 STREAM_XATTR_SOLARIS,
2383 STREAM_XATTR_SOLARIS_SYS
2386 static int os_default_xattr_streams[1] = {
2387 STREAM_XATTR_SOLARIS
2389 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2392 * This code creates a temporary cache with entries for each xattr which has
2393 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2395 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2397 xattr_link_cache_entry_t *ptr;
2399 foreach_alist(ptr, jcr->xattr_data->u.build->link_cache) {
2400 if (ptr && ptr->inum == inum) {
2407 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2409 xattr_link_cache_entry_t *ptr;
2411 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2412 memset(ptr, 0, sizeof(xattr_link_cache_entry_t));
2414 bstrncpy(ptr->target, target, sizeof(ptr->target));
2416 if (!jcr->xattr_data->u.build->link_cache) {
2417 jcr->xattr_data->u.build->link_cache = New(alist(10, not_owned_by_alist));
2419 jcr->xattr_data->u.build->link_cache->append(ptr);
2422 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2424 * This function returns true if a non default extended system attribute
2425 * list is associated with fd and returns false when an error has occured
2426 * or when only extended system attributes other than archive,
2427 * av_modified or crtime are set.
2429 * The function returns true for the following cases:
2431 * - any extended system attribute other than the default attributes
2432 * ('archive', 'av_modified' and 'crtime') is set
2433 * - nvlist has NULL name string
2434 * - nvpair has data type of 'nvlist'
2435 * - default data type.
2437 static bool solaris_has_non_transient_extensible_attributes(int fd)
2445 bool retval = false;
2447 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2452 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2453 name = nvpair_name(pair);
2456 fattr = name_to_attr(name);
2462 type = nvpair_type(pair);
2464 case DATA_TYPE_BOOLEAN_VALUE:
2465 if (nvpair_value_boolean_value(pair, &value) != 0) {
2468 if (value && fattr != F_ARCHIVE &&
2469 fattr != F_AV_MODIFIED) {
2474 case DATA_TYPE_UINT64_ARRAY:
2475 if (fattr != F_CRTIME) {
2480 case DATA_TYPE_NVLIST:
2488 if (response != NULL) {
2489 nvlist_free(response);
2493 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2495 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2497 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2498 * There is no need to store those acls as we already store the stat bits too.
2500 static bool acl_is_trivial(int count, aclent_t *entries)
2505 for (n = 0; n < count; n++) {
2507 if (!(ace->a_type == USER_OBJ ||
2508 ace->a_type == GROUP_OBJ ||
2509 ace->a_type == OTHER_OBJ ||
2510 ace->a_type == CLASS_OBJ))
2515 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2517 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2520 #ifdef HAVE_EXTENDED_ACL
2525 * See if this attribute has an ACL
2527 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2528 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2530 * See if there is a non trivial acl on the file.
2532 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2533 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2538 return bxattr_exit_ok;
2541 _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2542 attrname, jcr->last_fname, be.bstrerror());
2543 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2544 attrname, jcr->last_fname, be.bstrerror());
2545 return bxattr_exit_error;
2550 #if defined(ACL_SID_FMT)
2552 * New format flag added in newer Solaris versions.
2554 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2556 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2557 #endif /* ACL_SID_FMT */
2559 *acl_text = acl_totext(aclp, flags);
2567 return bxattr_exit_ok;
2568 #else /* HAVE_EXTENDED_ACL */
2570 aclent_t *acls = NULL;
2573 * See if this attribute has an ACL
2576 n = facl(fd, GETACLCNT, 0, NULL);
2578 n = acl(attrname, GETACLCNT, 0, NULL);
2581 if (n >= MIN_ACL_ENTRIES) {
2582 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2583 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2584 acl(attrname, GETACL, n, acls) != n) {
2590 return bxattr_exit_ok;
2593 _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2594 attrname, jcr->last_fname, be.bstrerror());
2595 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2596 attrname, jcr->last_fname, be.bstrerror());
2598 return bxattr_exit_error;
2603 * See if there is a non trivial acl on the file.
2605 if (!acl_is_trivial(n, acls)) {
2606 if ((*acl_text = acltotext(acls, n)) == NULL) {
2610 _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2611 attrname, jcr->last_fname, be.bstrerror());
2612 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2613 attrname, jcr->last_fname, be.bstrerror());
2615 return bxattr_exit_error;
2625 return bxattr_exit_ok;
2626 #endif /* HAVE_EXTENDED_ACL */
2628 #else /* HAVE_ACL */
2629 return bxattr_exit_ok;
2630 #endif /* HAVE_ACL */
2634 * Forward declaration for recursive function call.
2636 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2639 * Save an extended or extensible attribute.
2640 * This is stored as an opaque stream of bytes with the following encoding:
2642 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2644 * or for a hardlinked or symlinked attribute
2646 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2648 * xattr_name can be a subpath relative to the file the xattr is on.
2649 * stat_buffer is the string representation of the stat struct.
2650 * acl_string is an acl text when a non trivial acl is set on the xattr.
2651 * actual_xattr_data is the content of the xattr file.
2653 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2654 const char *attrname, bool toplevel_hidden_dir, int stream)
2659 xattr_link_cache_entry_t *xlce;
2660 char target_attrname[PATH_MAX];
2661 char link_source[PATH_MAX];
2662 char *acl_text = NULL;
2663 char attribs[MAXSTRING];
2664 char buffer[XATTR_BUFSIZ];
2665 bxattr_exit_code retval = bxattr_exit_error;
2667 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2670 * Get the stats of the extended or extensible attribute.
2672 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2677 retval = bxattr_exit_ok;
2681 _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2682 target_attrname, jcr->last_fname, be.bstrerror());
2683 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2684 target_attrname, jcr->last_fname, be.bstrerror());
2690 * Based on the filetype perform the correct action. We support most filetypes here, more
2691 * then the actual implementation on Solaris supports so some code may never get executed
2692 * due to limitations in the implementation.
2694 switch (st.st_mode & S_IFMT) {
2699 * Get any acl on the xattr.
2701 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2705 * The current implementation of xattr on Solaris doesn't support this,
2706 * but if it ever does we are prepared.
2707 * Encode the stat struct into an ASCII representation.
2709 encode_stat(attribs, &st, sizeof(st), 0, stream);
2710 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2711 target_attrname, 0, attribs, 0,
2712 (acl_text) ? acl_text : "", 0);
2716 * Get any acl on the xattr.
2718 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2722 * See if this is the toplevel_hidden_dir being saved.
2724 if (toplevel_hidden_dir) {
2726 * Save the data for later storage when we encounter a real xattr.
2727 * We store the data in the jcr->xattr_data->u.build->content buffer
2728 * and flush that just before sending out the first real xattr.
2729 * Encode the stat struct into an ASCII representation and jump
2730 * out of the function.
2732 encode_stat(attribs, &st, sizeof(st), 0, stream);
2733 cnt = bsnprintf(buffer, sizeof(buffer),
2735 target_attrname, 0, attribs, 0,
2736 (acl_text) ? acl_text : "", 0);
2737 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2738 jcr->xattr_data->u.build->content_length = cnt;
2742 * The current implementation of xattr on Solaris doesn't support this,
2743 * but if it ever does we are prepared.
2744 * Encode the stat struct into an ASCII representation.
2746 encode_stat(attribs, &st, sizeof(st), 0, stream);
2747 cnt = bsnprintf(buffer, sizeof(buffer),
2749 target_attrname, 0, attribs, 0,
2750 (acl_text) ? acl_text : "", 0);
2755 * If this is a hardlinked file check the inode cache for a hit.
2757 if (st.st_nlink > 1) {
2759 * See if the cache already knows this inode number.
2761 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2763 * Generate a xattr encoding with the reference to the target in there.
2765 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2766 cnt = bsnprintf(buffer, sizeof(buffer),
2768 target_attrname, 0, attribs, 0, xlce->target, 0);
2769 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2770 jcr->xattr_data->u.build->content_length = cnt;
2771 retval = send_xattr_stream(jcr, stream);
2774 * For a hard linked file we are ready now, no need to recursively
2775 * save the attributes.
2781 * Store this hard linked file in the cache.
2782 * Store the name relative to the top level xattr space.
2784 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2788 * Get any acl on the xattr.
2790 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2795 * Encode the stat struct into an ASCII representation.
2797 encode_stat(attribs, &st, sizeof(st), 0, stream);
2798 cnt = bsnprintf(buffer, sizeof(buffer),
2800 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2803 * Open the extended or extensible attribute file.
2805 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2810 retval = bxattr_exit_ok;
2814 _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2815 target_attrname, jcr->last_fname, be.bstrerror());
2816 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2817 target_attrname, jcr->last_fname, be.bstrerror());
2824 * The current implementation of xattr on Solaris doesn't support this, but if it
2825 * ever does we are prepared.
2826 * Encode the stat struct into an ASCII representation.
2828 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2833 retval = bxattr_exit_ok;
2837 _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2838 target_attrname, jcr->last_fname, be.bstrerror());
2839 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2840 target_attrname, jcr->last_fname, be.bstrerror());
2846 * Generate a xattr encoding with the reference to the target in there.
2848 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2849 cnt = bsnprintf(buffer, sizeof(buffer),
2851 target_attrname, 0, attribs, 0, link_source, 0);
2852 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2853 jcr->xattr_data->u.build->content_length = cnt;
2854 retval = send_xattr_stream(jcr, stream);
2856 if (retval == bxattr_exit_ok) {
2857 jcr->xattr_data->u.build->nr_saved++;
2861 * For a soft linked file we are ready now, no need to recursively save the attributes.
2869 * See if this is the first real xattr being saved.
2870 * If it is save the toplevel_hidden_dir attributes first.
2871 * This is easy as its stored already in the
2872 * jcr->xattr_data->u.build->content buffer.
2874 if (jcr->xattr_data->u.build->nr_saved == 0) {
2875 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2876 if (retval != bxattr_exit_ok) {
2879 jcr->xattr_data->u.build->nr_saved++;
2882 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2883 jcr->xattr_data->u.build->content_length = cnt;
2886 * Only dump the content of regular files.
2888 switch (st.st_mode & S_IFMT) {
2890 if (st.st_size > 0) {
2892 * Protect ourself against things getting out of hand.
2894 if (st.st_size >= MAX_XATTR_STREAM) {
2896 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2897 jcr->last_fname, MAX_XATTR_STREAM);
2901 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2902 jcr->xattr_data->u.build->content =
2903 check_pool_memory_size(jcr->xattr_data->u.build->content,
2904 jcr->xattr_data->u.build->content_length + cnt);
2905 memcpy(jcr->xattr_data->u.build->content +
2906 jcr->xattr_data->u.build->content_length, buffer, cnt);
2907 jcr->xattr_data->u.build->content_length += cnt;
2912 _("Unable to read content of xattr %s on file \"%s\"\n"),
2913 target_attrname, jcr->last_fname);
2914 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2915 target_attrname, jcr->last_fname);
2926 * We build a new xattr stream send it to the SD.
2928 retval = send_xattr_stream(jcr, stream);
2929 if (retval != bxattr_exit_ok) {
2932 jcr->xattr_data->u.build->nr_saved++;
2935 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2936 * available on this extended attribute.
2938 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2941 * The recursive call could change our working dir so change back to the wanted workdir.
2943 if (fchdir(fd) < 0) {
2948 retval = bxattr_exit_ok;
2952 _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2953 jcr->last_fname, be.bstrerror());
2954 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2955 jcr->last_fname, fd, be.bstrerror());
2961 if (acl_text != NULL) {
2970 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2973 int fd, filefd = -1, attrdirfd = -1;
2976 char current_xattr_namespace[PATH_MAX];
2977 bxattr_exit_code retval = bxattr_exit_error;
2980 * Determine what argument to use. Use attr_parent when set
2981 * (recursive call) or jcr->last_fname for first call. Also save
2982 * the current depth of the xattr_space we are in.
2986 if (xattr_namespace) {
2987 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2988 xattr_namespace, attr_parent);
2990 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2993 name = jcr->last_fname;
2994 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2998 * Open the file on which to save the xattrs read-only.
3000 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
3005 retval = bxattr_exit_ok;
3009 _("Unable to open file \"%s\": ERR=%s\n"),
3010 jcr->last_fname, be.bstrerror());
3011 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
3012 jcr->last_fname, be.bstrerror());
3018 * Open the xattr naming space.
3020 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3026 * Gentile way of the system saying this type of xattr layering is not supported.
3027 * Which is not problem we just forget about this this xattr.
3028 * But as this is not an error we return a positive return value.
3030 retval = bxattr_exit_ok;
3033 retval = bxattr_exit_ok;
3037 _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
3038 name, jcr->last_fname, be.bstrerror());
3039 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
3040 name, jcr->last_fname, be.bstrerror());
3046 * We need to change into the attribute directory to determine if each of the
3047 * attributes should be saved.
3049 if (fchdir(attrdirfd) < 0) {
3053 _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3054 jcr->last_fname, be.bstrerror());
3055 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
3056 jcr->last_fname, attrdirfd, be.bstrerror());
3061 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
3062 * else because the readdir returns "." entry after the extensible attr entry.
3063 * And as we want this entry before anything else we better just save its data.
3066 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
3067 true, STREAM_XATTR_SOLARIS);
3069 if ((fd = dup(attrdirfd)) == -1 ||
3070 (dirp = fdopendir(fd)) == (DIR *)NULL) {
3074 _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
3075 jcr->last_fname, be.bstrerror());
3076 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
3077 jcr->last_fname, fd, be.bstrerror());
3083 * Walk the namespace.
3085 while ((dp = readdir(dirp)) != NULL) {
3087 * Skip only the toplevel . dir.
3089 if (!attr_parent && bstrcmp(dp->d_name, "."))
3093 * Skip all .. directories
3095 if (bstrcmp(dp->d_name, ".."))
3098 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
3099 current_xattr_namespace, dp->d_name, jcr->last_fname);
3101 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3103 * We are not interested in read-only extensible attributes.
3105 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
3106 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
3107 current_xattr_namespace, dp->d_name, jcr->last_fname);
3113 * We are only interested in read-write extensible attributes
3114 * when they contain non-transient values.
3116 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
3118 * Determine if there are non-transient system attributes at the toplevel.
3119 * We need to provide a fd to the open file.
3121 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
3122 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
3123 current_xattr_namespace, dp->d_name, jcr->last_fname);
3130 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3131 false, STREAM_XATTR_SOLARIS_SYS);
3134 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
3139 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3140 false, STREAM_XATTR_SOLARIS);
3144 retval = bxattr_exit_ok;
3147 if (attrdirfd != -1)
3155 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr,
3157 const char *attrname,
3160 #ifdef HAVE_EXTENDED_ACL
3164 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
3166 _("Unable to convert acl from text on file \"%s\"\n"),
3168 return bxattr_exit_error;
3171 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
3172 acl_set(attrname, aclp) != 0) {
3176 _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3177 attrname, jcr->last_fname, be.bstrerror());
3178 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3179 attrname, jcr->last_fname, be.bstrerror());
3180 return bxattr_exit_error;
3186 return bxattr_exit_ok;
3188 #else /* HAVE_EXTENDED_ACL */
3190 aclent_t *acls = NULL;
3192 acls = aclfromtext(acl_text, &n);
3194 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
3195 acl(attrname, SETACL, n, acls) != 0) {
3199 _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3200 attrname, jcr->last_fname, be.bstrerror());
3201 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3202 attrname, jcr->last_fname, be.bstrerror());
3203 return bxattr_exit_error;
3210 return bxattr_exit_ok;
3212 #endif /* HAVE_EXTENDED_ACL */
3215 #endif /* HAVE_ACL */
3217 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr,
3220 uint32_t content_length)
3223 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
3224 int used_bytes, cnt;
3225 char *bp, *target_attrname, *attribs;
3226 char *linked_target = NULL;
3227 char *acl_text = NULL;
3231 struct timeval times[2];
3232 bxattr_exit_code retval = bxattr_exit_error;
3235 * Parse the xattr stream. First the part that is the same for all xattrs.
3240 * The name of the target xattr has a leading / we are not interested
3241 * in that so skip it when decoding the string. We always start a the /
3242 * of the xattr space anyway.
3244 target_attrname = content + 1;
3245 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
3246 (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3252 * Open the file on which to restore the xattrs read-only.
3254 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
3258 _("Unable to open file \"%s\": ERR=%s\n"),
3259 jcr->last_fname, be.bstrerror());
3260 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
3261 jcr->last_fname, be.bstrerror());
3266 * Open the xattr naming space and make it the current working dir.
3268 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3272 _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
3273 jcr->last_fname, be.bstrerror());
3274 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
3275 jcr->last_fname, be.bstrerror());
3279 if (fchdir(attrdirfd) < 0) {
3283 _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3284 jcr->last_fname, be.bstrerror());
3285 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
3286 jcr->last_fname, attrdirfd, be.bstrerror());
3291 * Try to open the correct xattr subdir based on the target_attrname given.
3292 * e.g. check if its a subdir attrname. Each / in the string makes us go
3295 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
3298 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
3302 _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3303 target_attrname, jcr->last_fname, be.bstrerror());
3304 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3305 target_attrname, jcr->last_fname, be.bstrerror());
3313 * Open the xattr naming space.
3315 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3319 _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
3320 target_attrname, jcr->last_fname, be.bstrerror());
3321 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
3322 target_attrname, jcr->last_fname, be.bstrerror());
3330 * Make the xattr space our current workingdir.
3332 if (fchdir(attrdirfd) < 0) {
3336 _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
3337 target_attrname, jcr->last_fname, be.bstrerror());
3338 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
3339 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
3343 target_attrname = ++bp;
3347 * Decode the attributes from the stream.
3349 decode_stat(attribs, &st, sizeof(st), &inum);
3352 * Decode the next field (acl_text).
3354 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
3355 (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3361 * Based on the filetype perform the correct action. We support most filetypes here, more
3362 * then the actual implementation on Solaris supports so some code may never get executed
3363 * due to limitations in the implementation.
3365 switch (st.st_mode & S_IFMT) {
3368 * The current implementation of xattr on Solaris doesn't support this,
3369 * but if it ever does we are prepared.
3371 unlinkat(attrdirfd, target_attrname, 0);
3372 if (mkfifo(target_attrname, st.st_mode) < 0) {
3376 _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3377 target_attrname, jcr->last_fname, be.bstrerror());
3378 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
3379 target_attrname, jcr->last_fname, be.bstrerror());
3386 * The current implementation of xattr on Solaris doesn't support this,
3387 * but if it ever does we are prepared.
3389 unlinkat(attrdirfd, target_attrname, 0);
3390 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3394 _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3395 target_attrname, jcr->last_fname, be.bstrerror());
3396 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3397 target_attrname, jcr->last_fname, be.bstrerror());
3403 * If its not the hidden_dir create the entry.
3404 * The current implementation of xattr on Solaris doesn't support this,
3405 * but if it ever does we are prepared.
3407 if (!bstrcmp(target_attrname, ".")) {
3408 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3409 if (mkdir(target_attrname, st.st_mode) < 0) {
3412 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3413 target_attrname, jcr->last_fname, be.bstrerror());
3414 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3415 target_attrname, jcr->last_fname, be.bstrerror());
3422 * See if this is a hard linked file. e.g. inum != 0
3427 unlinkat(attrdirfd, target_attrname, 0);
3428 if (link(linked_target, target_attrname) < 0) {
3432 _("Unable to link 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 link 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;
3445 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3446 (used_bytes = (bp - content)) >= (int32_t)content_length) {
3450 if (used_bytes < (int32_t)(content_length - 1))
3454 * Restore the actual xattr.
3456 if (!is_extensible) {
3457 unlinkat(attrdirfd, target_attrname, 0);
3460 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3464 _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3465 target_attrname, jcr->last_fname, be.bstrerror());
3466 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3467 target_attrname, jcr->last_fname, be.bstrerror());
3473 * Restore the actual data.
3475 if (st.st_size > 0) {
3476 used_bytes = (data - content);
3477 cnt = content_length - used_bytes;
3480 * Do a sanity check, the st.st_size should be the same as the number of bytes
3481 * we have available as data of the stream.
3483 if (cnt != st.st_size) {
3485 _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3486 target_attrname, jcr->last_fname);
3487 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3488 target_attrname, jcr->last_fname);
3493 cnt = write(attrfd, data, cnt);
3498 _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3499 target_attrname, jcr->last_fname, be.bstrerror());
3500 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3501 target_attrname, jcr->last_fname, be.bstrerror());
3507 cnt = content_length - used_bytes;
3513 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3517 if (symlink(linked_target, target_attrname) < 0) {
3521 _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3522 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3523 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3524 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3529 * Successfully restored xattr.
3531 retval = bxattr_exit_ok;
3538 * Restore owner and acl for non extensible attributes.
3540 if (!is_extensible) {
3541 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3547 * Gentile way of the system saying this type of xattr layering is not supported.
3548 * But as this is not an error we return a positive return value.
3550 retval = bxattr_exit_ok;
3553 retval = bxattr_exit_ok;
3557 _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3558 target_attrname, jcr->last_fname, be.bstrerror());
3559 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3560 target_attrname, jcr->last_fname, be.bstrerror());
3567 if (acl_text && *acl_text)
3568 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3570 #endif /* HAVE_ACL */
3573 * For a non extensible attribute restore access and modification time on the xattr.
3575 if (!is_extensible) {
3576 times[0].tv_sec = st.st_atime;
3577 times[0].tv_usec = 0;
3578 times[1].tv_sec = st.st_mtime;
3579 times[1].tv_usec = 0;
3581 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3585 _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3586 target_attrname, jcr->last_fname, be.bstrerror());
3587 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3588 target_attrname, jcr->last_fname, be.bstrerror());
3594 * Successfully restored xattr.
3596 retval = bxattr_exit_ok;
3601 _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3603 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3610 if (attrdirfd != -1) {
3619 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3622 bxattr_exit_code retval = bxattr_exit_ok;
3625 * First see if extended attributes or extensible attributes are present.
3626 * If not just pretend things went ok.
3628 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3629 jcr->xattr_data->u.build->nr_saved = 0;
3632 * As we change the cwd in the save function save the current cwd
3633 * for restore after return from the solaris_save_xattrs function.
3635 getcwd(cwd, sizeof(cwd));
3636 retval = solaris_save_xattrs(jcr, NULL, NULL);
3638 if (jcr->xattr_data->u.build->link_cache) {
3639 delete jcr->xattr_data->u.build->link_cache;
3640 jcr->xattr_data->u.build->link_cache = NULL;
3646 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr,
3649 uint32_t content_length)
3652 bool is_extensible = false;
3653 bxattr_exit_code retval;
3656 * First make sure we can restore xattr on the filesystem.
3659 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3660 case STREAM_XATTR_SOLARIS_SYS:
3661 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3663 _("Failed to restore extensible attributes on file \"%s\"\n"),
3665 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3667 return bxattr_exit_error;
3670 is_extensible = true;
3673 case STREAM_XATTR_SOLARIS:
3674 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3676 _("Failed to restore extended attributes on file \"%s\"\n"),
3678 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3680 return bxattr_exit_error;
3684 return bxattr_exit_error;
3688 * As we change the cwd in the restore function save the current cwd
3689 * for restore after return from the solaris_restore_xattrs function.
3691 getcwd(cwd, sizeof(cwd));
3692 retval = solaris_restore_xattrs(jcr, is_extensible, content, content_length);
3699 * Function pointers to the build and parse function to use for these xattrs.
3701 static bxattr_exit_code (*os_build_xattr_streams)
3702 (JCR *jcr, FF_PKT *ff_pkt) =
3703 solaris_build_xattr_streams;
3704 static bxattr_exit_code (*os_parse_xattr_streams)
3705 (JCR *jcr, int stream, char *content, uint32_t content_length) =
3706 solaris_parse_xattr_streams;
3708 #endif /* defined(HAVE_SUN_OS) */
3711 * Entry points when compiled with support for XATTRs on a supported platform.
3713 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3716 * See if we are changing from one device to an other.
3717 * We save the current device we are scanning and compare
3718 * it with the current st_dev in the last stat performed on
3719 * the file we are currently storing.
3721 if (jcr->xattr_data->current_dev != ff_pkt->statp.st_dev) {
3723 * Reset the acl save flags.
3725 jcr->xattr_data->flags = 0;
3726 jcr->xattr_data->flags |= BXATTR_FLAG_SAVE_NATIVE;
3729 * Save that we started scanning a new filesystem.
3731 jcr->xattr_data->current_dev = ff_pkt->statp.st_dev;
3734 if ((jcr->xattr_data->flags & BXATTR_FLAG_SAVE_NATIVE) && os_parse_xattr_streams) {
3735 return os_build_xattr_streams(jcr, ff_pkt);
3737 return bxattr_exit_ok;
3741 bxattr_exit_code parse_xattr_streams(JCR *jcr,
3744 uint32_t content_length)
3751 * See if we are changing from one device to an other.
3752 * We save the current device we are restoring to and compare
3753 * it with the current st_dev in the last stat performed on
3754 * the file we are currently restoring.
3756 ret = lstat(jcr->last_fname, &st);
3763 return bxattr_exit_ok;
3766 _("Unable to stat file \"%s\": ERR=%s\n"),
3767 jcr->last_fname, be.bstrerror());
3768 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
3769 jcr->last_fname, be.bstrerror());
3770 return bxattr_exit_error;
3777 if (jcr->xattr_data->current_dev != st.st_dev) {
3779 * Reset the acl save flags.
3781 jcr->xattr_data->flags = 0;
3782 jcr->xattr_data->flags |= BXATTR_FLAG_RESTORE_NATIVE;
3785 * Save that we started restoring to a new filesystem.
3787 jcr->xattr_data->current_dev = st.st_dev;
3791 * See if we are still restoring native xattr to this filesystem.
3793 if ((jcr->xattr_data->flags & BXATTR_FLAG_RESTORE_NATIVE) && os_parse_xattr_streams) {
3795 * See if we can parse this stream, and ifso give it a try.
3797 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3798 if (os_default_xattr_streams[cnt] == stream) {
3799 return os_parse_xattr_streams(jcr, stream, content, content_length);
3804 * Increment error count but don't log an error again for the same filesystem.
3806 jcr->xattr_data->u.parse->nr_errors++;
3807 return bxattr_exit_ok;
3811 * Issue a warning and discard the message. But pretend the restore was ok.
3813 Jmsg2(jcr, M_WARNING, 0,
3814 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3815 jcr->last_fname, stream);
3816 return bxattr_exit_error;