2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2011 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 MMVIII
56 #if !defined(HAVE_XATTR)
58 * Entry points when compiled without support for XATTRs or on an unsupported platform.
60 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
62 return bxattr_exit_fatal;
65 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
67 return bxattr_exit_fatal;
71 * Send a XATTR stream to the SD.
73 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
75 BSOCK *sd = jcr->store_bsock;
77 #ifdef FD_NO_SEND_TEST
78 return bxattr_exit_ok;
84 if (jcr->xattr_data->content_length <= 0) {
85 return bxattr_exit_ok;
91 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
92 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
94 return bxattr_exit_fatal;
98 * Send the buffer to the storage deamon
100 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
102 sd->msg = jcr->xattr_data->content;
103 sd->msglen = jcr->xattr_data->content_length;
107 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
109 return bxattr_exit_fatal;
112 jcr->JobBytes += sd->msglen;
114 if (!sd->signal(BNET_EOD)) {
115 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
117 return bxattr_exit_fatal;
119 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
120 return bxattr_exit_ok;
124 * First some generic functions for OSes that use the same xattr encoding scheme.
125 * Currently for all OSes except for Solaris.
127 #if !defined(HAVE_SUN_OS)
128 static void xattr_drop_internal_table(alist *xattr_value_list)
130 xattr_t *current_xattr;
133 * Walk the list of xattrs and free allocated memory on traversing.
135 foreach_alist(current_xattr, xattr_value_list) {
137 * See if we can shortcut.
139 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
142 free(current_xattr->name);
144 if (current_xattr->value_length > 0)
145 free(current_xattr->value);
150 delete xattr_value_list;
154 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
155 * which encodes one or more xattr_t structures.
157 * The Serialized stream consists of the following elements:
158 * magic - A magic string which makes it easy to detect any binary incompatabilites
159 * name_length - The length of the following xattr name
160 * name - The name of the extended attribute
161 * value_length - The length of the following xattr data
162 * value - The actual content of the extended attribute
164 * This is repeated 1 or more times.
167 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, alist *xattr_value_list)
169 xattr_t *current_xattr;
173 * Make sure the serialized stream fits in the poolmem buffer.
174 * We allocate some more to be sure the stream is gonna fit.
176 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
177 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
180 * Walk the list of xattrs and serialize the data.
182 foreach_alist(current_xattr, xattr_value_list) {
184 * See if we can shortcut.
186 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
189 ser_uint32(current_xattr->magic);
190 ser_uint32(current_xattr->name_length);
191 ser_bytes(current_xattr->name, current_xattr->name_length);
193 ser_uint32(current_xattr->value_length);
194 if (current_xattr->value_length > 0 && current_xattr->value) {
195 ser_bytes(current_xattr->value, current_xattr->value_length);
197 Dmsg3(100, "Backup xattr named %s, value %*s\n",
198 current_xattr->name, current_xattr->value, current_xattr->value);
200 Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
204 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
205 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
207 return jcr->xattr_data->content_length;
210 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
213 xattr_t *current_xattr;
214 bxattr_exit_code retval = bxattr_exit_ok;
217 * Parse the stream and call restore_xattr_on_file for each extended attribute.
219 * Start unserializing the data. We keep on looping while we have not
220 * unserialized all bytes in the stream.
222 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
223 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
225 * First make sure the magic is present. This way we can easily catch corruption.
226 * Any missing MAGIC is fatal we do NOT try to continue.
228 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
229 unser_uint32(current_xattr->magic);
230 if (current_xattr->magic != XATTR_MAGIC) {
231 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
233 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
236 return bxattr_exit_error;
240 * Decode the valuepair. First decode the length of the name.
242 unser_uint32(current_xattr->name_length);
243 if (current_xattr->name_length == 0) {
244 Mmsg1(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
246 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
249 return bxattr_exit_error;
253 * Allocate room for the name and decode its content.
255 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
256 unser_bytes(current_xattr->name, current_xattr->name_length);
259 * The xattr_name needs to be null terminated.
261 current_xattr->name[current_xattr->name_length] = '\0';
264 * Decode the value length.
266 unser_uint32(current_xattr->value_length);
268 if (current_xattr->value_length > 0) {
270 * Allocate room for the value and decode its content.
272 current_xattr->value = (char *)malloc(current_xattr->value_length);
273 unser_bytes(current_xattr->value, current_xattr->value_length);
275 Dmsg3(100, "Restoring xattr named %s, value %*s\n",
276 current_xattr->name, current_xattr->value, current_xattr->value);
278 current_xattr->value = NULL;
279 Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
282 xattr_value_list->append(current_xattr);
285 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
291 * This is a supported OS, See what kind of interface we should use.
293 #if defined(HAVE_AIX_OS)
295 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
296 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
297 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
298 #error "Missing full support for the Extended Attributes (EA) functions."
304 #error "Missing sys/ea.h header file"
308 * Define the supported XATTR streams for this OS
310 static int os_default_xattr_streams[1] = { STREAM_XATTR_AIX };
313 * Fallback to the non l-functions when those are not available.
315 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
318 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
321 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
322 #define llistea listea
325 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
328 char *xattr_list, *bp;
329 int cnt, xattr_count = 0;
330 uint32_t name_length;
331 int32_t xattr_list_len,
333 uint32_t expected_serialize_len = 0;
334 xattr_t *current_xattr = NULL;
335 alist *xattr_value_list = NULL;
336 bxattr_exit_code retval = bxattr_exit_error;
340 * First get the length of the available list with extended attributes.
342 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
343 switch (xattr_list_len) {
348 return bxattr_exit_ok;
351 * If the filesystem reports it doesn't support XATTRs we clear the
352 * BXATTR_FLAG_SAVE_NATIVE flag so we skip XATTR saves on all other files
353 * on the same filesystem. The BXATTR_FLAG_SAVE_NATIVE flags gets sets again
354 * when we change from one filesystem to an other.
356 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
357 return bxattr_exit_ok;
359 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
360 jcr->last_fname, be.bstrerror());
361 Dmsg2(100, "llistea error file=%s ERR=%s\n",
362 jcr->last_fname, be.bstrerror());
363 return bxattr_exit_error;
367 return bxattr_exit_ok;
373 * Allocate room for the extented attribute list.
375 xattr_list = (char *)malloc(xattr_list_len + 1);
376 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
379 * Get the actual list of extended attributes names for a file.
381 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
382 switch (xattr_list_len) {
387 retval = bxattr_exit_ok;
390 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
391 jcr->last_fname, be.bstrerror());
392 Dmsg2(100, "llistea error file=%s ERR=%s\n",
393 jcr->last_fname, be.bstrerror());
400 xattr_list[xattr_list_len] = '\0';
403 * Walk the list of extended attributes names and retrieve the data.
404 * We already count the bytes needed for serializing the stream later on.
407 while ((bp - xattr_list) + 1 < xattr_list_len) {
411 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
417 name_length = strlen(bp);
418 if (skip_xattr || name_length == 0) {
419 Dmsg1(100, "Skipping xattr named %s\n", bp);
420 bp = strchr(bp, '\0') + 1;
425 * Each xattr valuepair starts with a magic so we can parse it easier.
427 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
428 current_xattr->magic = XATTR_MAGIC;
429 expected_serialize_len += sizeof(current_xattr->magic);
432 * Allocate space for storing the name.
434 current_xattr->name_length = name_length;
435 current_xattr->name = (char *)malloc(current_xattr->name_length);
436 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
438 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
441 * First see how long the value is for the extended attribute.
443 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
444 switch (xattr_value_len) {
449 retval = bxattr_exit_ok;
452 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
453 jcr->last_fname, be.bstrerror());
454 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
455 jcr->last_fname, be.bstrerror());
460 current_xattr->value = NULL;
461 current_xattr->value_length = 0;
462 expected_serialize_len += sizeof(current_xattr->value_length);
466 * Allocate space for storing the value.
468 current_xattr->value = (char *)malloc(xattr_value_len);
469 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
471 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
472 if (xattr_value_len < 0) {
476 retval = bxattr_exit_ok;
479 Mmsg2(jcr->errmsg, _("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());
487 * Store the actual length of the value.
489 current_xattr->value_length = xattr_value_len;
490 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
493 * Protect ourself against things getting out of hand.
495 if (expected_serialize_len >= MAX_XATTR_STREAM) {
496 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
497 jcr->last_fname, MAX_XATTR_STREAM);
502 if (xattr_value_list == NULL) {
503 xattr_value_list = New(alist(10, not_owned_by_alist));
506 xattr_value_list->append(current_xattr);
507 current_xattr = NULL;
509 bp = strchr(bp, '\0') + 1;
514 xattr_list = (char *)NULL;
517 * If we found any xattr send them to the SD.
519 if (xattr_count > 0) {
521 * Serialize the datastream.
523 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
524 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
526 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
532 * Send the datastream to the SD.
534 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
536 retval = bxattr_exit_ok;
540 if (current_xattr != NULL) {
541 if (current_xattr->value != NULL) {
542 free(current_xattr->value);
544 if (current_xattr->name != NULL) {
545 free(current_xattr->name);
549 if (xattr_list != NULL) {
552 if (xattr_value_list != NULL) {
553 xattr_drop_internal_table(xattr_value_list);
558 static bxattr_exit_code aix_xattr_parse_streams(JCR *jcr, int stream)
560 xattr_t *current_xattr;
561 alist *xattr_value_list;
564 xattr_value_list = New(alist(10, not_owned_by_alist));
566 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
567 xattr_drop_internal_table(xattr_value_list);
568 return bxattr_exit_error;
571 foreach_alist(current_xattr, xattr_value_list) {
572 if (lsetea(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
579 * If the filesystem reports it doesn't support XATTRs we clear the
580 * BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores on all other files
581 * on the same filesystem. The BXATTR_FLAG_RESTORE_NATIVE flags gets sets again
582 * when we change from one filesystem to an other.
584 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
587 Mmsg2(jcr->errmsg, _("lsetea error on file \"%s\": ERR=%s\n"),
588 jcr->last_fname, be.bstrerror());
589 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
590 jcr->last_fname, be.bstrerror());
596 xattr_drop_internal_table(xattr_value_list);
597 return bxattr_exit_ok;
600 xattr_drop_internal_table(xattr_value_list);
601 return bxattr_exit_error;
605 * Function pointers to the build and parse function to use for these xattrs.
607 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_xattr_build_streams;
608 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = aix_xattr_parse_streams;
610 #elif defined(HAVE_IRIX_OS)
612 #include <sys/attributes.h>
615 * Define the supported XATTR streams for this OS
617 static int os_default_xattr_streams[1] = { STREAM_XATTR_IRIX };
618 static const char *xattr_acl_skiplist[1] = { NULL };
619 static const char *xattr_skiplist[1] = { NULL };
621 struct xattr_naming_space {
626 static xattr_naming_space xattr_naming_spaces[] = {
627 { "user.", ATTR_DONTFOLLOW },
628 { "root.", ATTR_ROOT | ATTR_DONTFOLLOW },
632 static bxattr_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
634 int cnt, length, xattr_count = 0;
635 attrlist_cursor_t cursor;
636 attrlist_t *attrlist;
637 attrlist_ent_t *attrlist_ent;
638 xattr_t *current_xattr = NULL;
639 alist *xattr_value_list = NULL;
640 uint32_t expected_serialize_len = 0;
641 bxattr_exit_code retval = bxattr_exit_error;
642 POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
645 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
646 memset(&cursor, 0, sizeof(attrlist_cursor_t));
648 if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
649 xattr_naming_spaces[cnt].flags, &cursor) != 0) {
652 retval = bxattr_exit_ok;
655 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
656 jcr->last_fname, be.bstrerror());
657 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
658 jcr->last_fname, be.bstrerror());
663 attrlist = (attrlist_t *)xattrbuf;
666 * Walk the available attributes.
668 for (cnt = 0; cnt < attrlist->al_count; cnt++) {
669 attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
672 * Each xattr valuepair starts with a magic so we can parse it easier.
674 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
675 current_xattr->magic = XATTR_MAGIC;
676 expected_serialize_len += sizeof(current_xattr->magic);
679 * Allocate space for storing the name.
680 * We store the name as <naming_space_name><xattr_name>
682 current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) + strlen(attrlist_ent->a_name) + 1;
683 current_xattr->name = (char *)malloc(current_xattr->name_length);
684 bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
685 xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
687 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
689 current_xattr->value_length = attrlist_ent->a_valuelen;
690 current_xattr->value = (char *)malloc(current_xattr->value_length);
693 * Retrieve the actual value of the xattr.
695 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
696 &length, xattr_naming_spaces[cnt].flags) != 0) {
700 retval = bxattr_exit_ok;
704 * The buffer for the xattr isn't big enough. the value of
705 * current_xattr->value_length is updated with the actual size
706 * of the xattr. So we free the old buffer and create a new one
709 free(current_xattr->value);
710 current_xattr->value = (char *)malloc(current_xattr->value_length);
711 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
712 &length, xattr_naming_spaces[cnt].flags) != 0) {
716 retval = bxattr_exit_ok;
719 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
720 jcr->last_fname, be.bstrerror());
721 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
722 jcr->last_fname, be.bstrerror());
726 current_xattr->value_length = length;
730 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
731 jcr->last_fname, be.bstrerror());
732 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
733 jcr->last_fname, be.bstrerror());
737 current_xattr->value_length = length;
740 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
743 * Protect ourself against things getting out of hand.
745 if (expected_serialize_len >= MAX_XATTR_STREAM) {
746 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
747 jcr->last_fname, MAX_XATTR_STREAM);
751 if (xattr_value_list == NULL) {
752 xattr_value_list = New(alist(10, not_owned_by_alist));
755 xattr_value_list->append(current_xattr);
756 current_xattr = NULL;
761 * See if there are more attributes available for a next run of attr_list.
763 if (attrlist->al_more == 0) {
770 * If we found any xattr send them to the SD.
772 if (xattr_count > 0) {
774 * Serialize the datastream.
776 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
777 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
779 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
785 * Send the datastream to the SD.
787 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
789 retval = bxattr_exit_ok;
793 if (current_xattr != NULL) {
794 if (current_xattr->value != NULL) {
795 free(current_xattr->value);
797 if (current_xattr->name != NULL) {
798 free(current_xattr->name);
802 free_pool_memory(xattrbuf);
804 if (xattr_value_list != NULL) {
805 xattr_drop_internal_table(xattr_value_list);
810 static bxattr_exit_code irix_xattr_parse_streams(JCR *jcr, int stream)
813 int cnt, cmp_size, name_space_index, flags;
814 xattr_t *current_xattr;
815 alist *xattr_value_list;
816 bxattr_exit_code retval = bxattr_exit_error;
819 xattr_value_list = New(alist(10, not_owned_by_alist));
821 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
822 xattr_drop_internal_table(xattr_value_list);
823 return bxattr_exit_error;
826 foreach_alist(current_xattr, xattr_value_list) {
828 * See to what namingspace this xattr belongs to.
830 name_space_index = 0;
831 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
832 cmp_size = strlen(xattr_naming_spaces[cnt].name);
833 if (!strncasecmp(current_xattr->name,
834 xattr_naming_spaces[cnt].name,
836 name_space_index = cnt;
842 * If we got a xattr that doesn't belong to an valid namespace complain.
844 if (name_space_index == 0) {
845 Mmsg2(jcr->errmsg, _("Received illegal xattr named %s on file \"%s\"\n"),
846 current_xattr->name, jcr->last_fname);
847 Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
848 current_xattr->name, jcr->last_fname);
853 * Restore the xattr first try to create the attribute from scratch.
855 flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
856 bp = strchr(current_xattr->name, '.');
857 if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
858 current_xattr->value_length, flags) != 0) {
861 retval = bxattr_exit_ok;
865 * The xattr already exists we need to replace it.
867 flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
868 if (attr_set(jcr->last_fname, bp, current_xattr->value,
869 current_xattr->value_length, flags) != 0) {
872 retval = bxattr_exit_ok;
875 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
876 jcr->last_fname, be.bstrerror());
877 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
878 jcr->last_fname, be.bstrerror());
884 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
885 jcr->last_fname, be.bstrerror());
886 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
887 jcr->last_fname, be.bstrerror());
893 xattr_drop_internal_table(xattr_value_list);
894 return bxattr_exit_ok;
897 xattr_drop_internal_table(xattr_value_list);
898 return bxattr_exit_error;
902 * Function pointers to the build and parse function to use for these xattrs.
904 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = irix_xattr_build_streams;
905 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = irix_xattr_parse_streams;
907 #elif defined(HAVE_DARWIN_OS) || \
908 defined(HAVE_LINUX_OS)
910 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
911 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
912 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
913 #error "Missing full support for the XATTR functions."
916 #ifdef HAVE_SYS_XATTR_H
917 #include <sys/xattr.h>
919 #error "Missing sys/xattr.h header file"
923 * Define the supported XATTR streams for this OS
925 #if defined(HAVE_DARWIN_OS)
926 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
927 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
928 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
929 #elif defined(HAVE_LINUX_OS)
930 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
931 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
932 static const char *xattr_skiplist[1] = { NULL };
936 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
937 * listxattr, getxattr and setxattr with an extra options argument
938 * which mimics the l variants of the functions when we specify
939 * XATTR_NOFOLLOW as the options value.
941 #if defined(HAVE_DARWIN_OS)
942 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
943 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
944 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
947 * Fallback to the non l-functions when those are not available.
949 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
950 #define lgetxattr getxattr
952 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
953 #define lsetxattr setxattr
955 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
956 #define llistxattr listxattr
960 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
963 char *xattr_list, *bp;
964 int cnt, xattr_count = 0;
965 uint32_t name_length;
966 int32_t xattr_list_len,
968 uint32_t expected_serialize_len = 0;
969 xattr_t *current_xattr = NULL;
970 alist *xattr_value_list = NULL;
971 bxattr_exit_code retval = bxattr_exit_error;
975 * First get the length of the available list with extended attributes.
977 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
978 switch (xattr_list_len) {
982 return bxattr_exit_ok;
985 * If the filesystem reports it doesn't support XATTRs we clear the
986 * BXATTR_FLAG_SAVE_NATIVE flag so we skip XATTR saves on all other files
987 * on the same filesystem. The BXATTR_FLAG_SAVE_NATIVE flags gets sets again
988 * when we change from one filesystem to an other.
990 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
991 return bxattr_exit_ok;
993 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
994 jcr->last_fname, be.bstrerror());
995 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
996 jcr->last_fname, be.bstrerror());
997 return bxattr_exit_error;
1001 return bxattr_exit_ok;
1007 * Allocate room for the extented attribute list.
1009 xattr_list = (char *)malloc(xattr_list_len + 1);
1010 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
1013 * Get the actual list of extended attributes names for a file.
1015 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
1016 switch (xattr_list_len) {
1020 retval = bxattr_exit_ok;
1023 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
1024 jcr->last_fname, be.bstrerror());
1025 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1026 jcr->last_fname, be.bstrerror());
1033 xattr_list[xattr_list_len] = '\0';
1036 * Walk the list of extended attributes names and retrieve the data.
1037 * We already count the bytes needed for serializing the stream later on.
1040 while ((bp - xattr_list) + 1 < xattr_list_len) {
1044 * On some OSes you also get the acls in the extented attribute list.
1045 * So we check if we are already backing up acls and if we do we
1046 * don't store the extended attribute with the same info.
1048 if (ff_pkt->flags & FO_ACL) {
1049 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1050 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1058 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1061 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1062 if (bstrcmp(bp, xattr_skiplist[cnt])) {
1069 name_length = strlen(bp);
1070 if (skip_xattr || name_length == 0) {
1071 Dmsg1(100, "Skipping xattr named %s\n", bp);
1072 bp = strchr(bp, '\0') + 1;
1077 * Each xattr valuepair starts with a magic so we can parse it easier.
1079 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1080 current_xattr->magic = XATTR_MAGIC;
1081 expected_serialize_len += sizeof(current_xattr->magic);
1084 * Allocate space for storing the name.
1086 current_xattr->name_length = name_length;
1087 current_xattr->name = (char *)malloc(current_xattr->name_length);
1088 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
1090 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1093 * First see how long the value is for the extended attribute.
1095 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1096 switch (xattr_value_len) {
1100 retval = bxattr_exit_ok;
1103 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1104 jcr->last_fname, be.bstrerror());
1105 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1106 jcr->last_fname, be.bstrerror());
1111 current_xattr->value = NULL;
1112 current_xattr->value_length = 0;
1113 expected_serialize_len += sizeof(current_xattr->value_length);
1117 * Allocate space for storing the value.
1119 current_xattr->value = (char *)malloc(xattr_value_len);
1120 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1122 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1123 if (xattr_value_len < 0) {
1126 retval = bxattr_exit_ok;
1129 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1130 jcr->last_fname, be.bstrerror());
1131 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1132 jcr->last_fname, be.bstrerror());
1137 * Store the actual length of the value.
1139 current_xattr->value_length = xattr_value_len;
1140 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1143 * Protect ourself against things getting out of hand.
1145 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1146 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1147 jcr->last_fname, MAX_XATTR_STREAM);
1152 if (xattr_value_list == NULL) {
1153 xattr_value_list = New(alist(10, not_owned_by_alist));
1156 xattr_value_list->append(current_xattr);
1157 current_xattr = NULL;
1159 bp = strchr(bp, '\0') + 1;
1164 xattr_list = (char *)NULL;
1167 * If we found any xattr send them to the SD.
1169 if (xattr_count > 0) {
1171 * Serialize the datastream.
1173 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1174 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1176 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1182 * Send the datastream to the SD.
1184 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1186 retval = bxattr_exit_ok;
1190 if (current_xattr != NULL) {
1191 if (current_xattr->value != NULL) {
1192 free(current_xattr->value);
1194 if (current_xattr->name != NULL) {
1195 free(current_xattr->name);
1197 free(current_xattr);
1199 if (xattr_list != NULL) {
1202 if (xattr_value_list != NULL) {
1203 xattr_drop_internal_table(xattr_value_list);
1208 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
1210 xattr_t *current_xattr;
1211 alist *xattr_value_list;
1214 xattr_value_list = New(alist(10, not_owned_by_alist));
1216 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1217 xattr_drop_internal_table(xattr_value_list);
1218 return bxattr_exit_error;
1221 foreach_alist(current_xattr, xattr_value_list) {
1222 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1226 case BXATTR_ENOTSUP:
1228 * If the filesystem reports it doesn't support XATTRs we clear the
1229 * BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores on all other files
1230 * on the same filesystem. The BXATTR_FLAG_RESTORE_NATIVE flags gets sets again
1231 * when we change from one filesystem to an other.
1233 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
1236 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
1237 jcr->last_fname, be.bstrerror());
1238 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1239 jcr->last_fname, be.bstrerror());
1245 xattr_drop_internal_table(xattr_value_list);
1246 return bxattr_exit_ok;
1249 xattr_drop_internal_table(xattr_value_list);
1250 return bxattr_exit_error;
1254 * Function pointers to the build and parse function to use for these xattrs.
1256 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
1257 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
1259 #elif defined(HAVE_FREEBSD_OS) || \
1260 defined(HAVE_NETBSD_OS) || \
1261 defined(HAVE_OPENBSD_OS)
1263 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1264 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1265 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1266 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1267 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1268 #error "Missing full support for the extattr functions."
1271 #ifdef HAVE_SYS_EXTATTR_H
1272 #include <sys/extattr.h>
1274 #error "Missing sys/extattr.h header file"
1277 #ifdef HAVE_LIBUTIL_H
1278 #include <libutil.h>
1281 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1282 #define extattr_get_link extattr_get_file
1284 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1285 #define extattr_set_link extattr_set_file
1287 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1288 #define extattr_list_link extattr_list_file
1291 #if defined(HAVE_FREEBSD_OS)
1292 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
1293 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1294 static const char *xattr_acl_skiplist[4] = { "system.posix1e.acl_access", "system.posix1e.acl_default", "system.nfs4.acl", NULL };
1295 static const char *xattr_skiplist[1] = { NULL };
1296 #elif defined(HAVE_NETBSD_OS)
1297 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
1298 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1299 static const char *xattr_acl_skiplist[1] = { NULL };
1300 static const char *xattr_skiplist[1] = { NULL };
1301 #elif defined(HAVE_OPENBSD_OS)
1302 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
1303 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1304 static const char *xattr_acl_skiplist[1] = { NULL };
1305 static const char *xattr_skiplist[1] = { NULL };
1308 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1312 int cnt, index, xattr_count = 0;
1313 int32_t xattr_list_len,
1315 uint32_t expected_serialize_len = 0;
1316 unsigned int namespace_index;
1318 char *current_attrnamespace = NULL;
1319 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1320 xattr_t *current_xattr = NULL;
1321 alist *xattr_value_list = NULL;
1322 bxattr_exit_code retval = bxattr_exit_error;
1326 * Loop over all available xattr namespaces.
1328 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
1329 attrnamespace = os_default_xattr_namespaces[namespace_index];
1332 * First get the length of the available list with extended attributes.
1333 * If we get EPERM on system namespace, don't return error.
1334 * This is expected for normal users trying to archive the system
1335 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1336 * they've decided to return EOPNOTSUPP instead.
1338 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1339 switch (xattr_list_len) {
1343 retval = bxattr_exit_ok;
1345 #if defined(EOPNOTSUPP)
1349 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1356 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1357 jcr->last_fname, be.bstrerror());
1358 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1359 jcr->last_fname, be.bstrerror());
1370 * Allocate room for the extented attribute list.
1372 xattr_list = (char *)malloc(xattr_list_len + 1);
1373 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
1376 * Get the actual list of extended attributes names for a file.
1378 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
1379 switch (xattr_list_len) {
1383 retval = bxattr_exit_ok;
1386 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1387 jcr->last_fname, be.bstrerror());
1388 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1389 jcr->last_fname, be.bstrerror());
1396 xattr_list[xattr_list_len] = '\0';
1399 * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
1400 * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
1402 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1403 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
1404 attrnamespace, jcr->last_fname);
1405 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1406 attrnamespace, jcr->last_fname);
1411 * Walk the list of extended attributes names and retrieve the data.
1412 * We already count the bytes needed for serializing the stream later on.
1414 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1418 * Print the current name into the buffer as its not null terminated we need to
1419 * use the length encoded in the string for copying only the needed bytes.
1421 cnt = xattr_list[index];
1422 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1423 cnt = ((int)sizeof(current_attrname) - 1);
1425 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1426 current_attrname[cnt] = '\0';
1429 * First make a xattr tuple of the current namespace and the name of the xattr.
1430 * e.g. something like user.<attrname> or system.<attrname>
1432 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
1435 * On some OSes you also get the acls in the extented attribute list.
1436 * So we check if we are already backing up acls and if we do we
1437 * don't store the extended attribute with the same info.
1439 if (ff_pkt->flags & FO_ACL) {
1440 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1441 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1449 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1452 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1453 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1461 Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1466 * Each xattr valuepair starts with a magic so we can parse it easier.
1468 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1469 current_xattr->magic = XATTR_MAGIC;
1470 expected_serialize_len += sizeof(current_xattr->magic);
1473 * Allocate space for storing the name.
1475 current_xattr->name_length = strlen(current_attrtuple);
1476 current_xattr->name = (char *)malloc(current_xattr->name_length);
1477 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
1479 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1482 * First see how long the value is for the extended attribute.
1484 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
1485 switch (xattr_value_len) {
1489 retval = bxattr_exit_ok;
1492 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1493 jcr->last_fname, be.bstrerror());
1494 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1495 jcr->last_fname, be.bstrerror());
1500 current_xattr->value = NULL;
1501 current_xattr->value_length = 0;
1502 expected_serialize_len += sizeof(current_xattr->value_length);
1506 * Allocate space for storing the value.
1508 current_xattr->value = (char *)malloc(xattr_value_len);
1509 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1511 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
1512 if (xattr_value_len < 0) {
1515 retval = bxattr_exit_ok;
1518 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1519 jcr->last_fname, be.bstrerror());
1520 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1521 jcr->last_fname, be.bstrerror());
1527 * Store the actual length of the value.
1529 current_xattr->value_length = xattr_value_len;
1530 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1533 * Protect ourself against things getting out of hand.
1535 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1536 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1537 jcr->last_fname, MAX_XATTR_STREAM);
1543 if (xattr_value_list == NULL) {
1544 xattr_value_list = New(alist(10, not_owned_by_alist));
1547 xattr_value_list->append(current_xattr);
1548 current_xattr = NULL;
1554 * Drop the local copy of the current_attrnamespace.
1556 actuallyfree(current_attrnamespace);
1557 current_attrnamespace = NULL;
1560 * We are done with this xattr list.
1563 xattr_list = (char *)NULL;
1567 * If we found any xattr send them to the SD.
1569 if (xattr_count > 0) {
1571 * Serialize the datastream.
1573 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1574 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1576 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1582 * Send the datastream to the SD.
1584 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1586 retval = bxattr_exit_ok;
1590 if (current_attrnamespace != NULL) {
1591 actuallyfree(current_attrnamespace);
1593 if (current_xattr != NULL) {
1594 if (current_xattr->value != NULL) {
1595 free(current_xattr->value);
1597 if (current_xattr->name != NULL) {
1598 free(current_xattr->name);
1600 free(current_xattr);
1602 if (xattr_list != NULL) {
1605 if (xattr_value_list != NULL) {
1606 xattr_drop_internal_table(xattr_value_list);
1611 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
1613 xattr_t *current_xattr;
1614 alist *xattr_value_list;
1615 int current_attrnamespace, cnt;
1616 char *attrnamespace, *attrname;
1619 xattr_value_list = New(alist(10, not_owned_by_alist));
1621 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1622 xattr_drop_internal_table(xattr_value_list);
1623 return bxattr_exit_error;
1626 foreach_alist(current_xattr, xattr_value_list) {
1628 * Try splitting the xattr_name into a namespace and name part.
1629 * The splitting character is a .
1631 attrnamespace = current_xattr->name;
1632 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1633 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1634 current_xattr->name, jcr->last_fname);
1635 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1636 current_xattr->name, jcr->last_fname);
1642 * Make sure the attrnamespace makes sense.
1644 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1645 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1646 attrnamespace, jcr->last_fname);
1647 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1648 attrnamespace, jcr->last_fname);
1653 * Try restoring the extended attribute.
1655 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1656 attrname, current_xattr->value, current_xattr->value_length);
1657 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1663 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1664 jcr->last_fname, be.bstrerror());
1665 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1666 jcr->last_fname, be.bstrerror());
1673 xattr_drop_internal_table(xattr_value_list);
1674 return bxattr_exit_ok;
1677 xattr_drop_internal_table(xattr_value_list);
1678 return bxattr_exit_error;
1682 * Function pointers to the build and parse function to use for these xattrs.
1684 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1685 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1687 #elif defined(HAVE_OSF1_OS)
1689 #if !defined(HAVE_GETPROPLIST) || \
1690 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1691 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1692 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1693 !defined(HAVE_SETPROPLIST)
1694 #error "Missing full support for the Extended Attributes functions."
1697 #ifdef HAVE_SYS_PROPLIST_H
1698 #include <sys/proplist.h>
1700 #error "Missing sys/proplist.h header file"
1704 * Define the supported XATTR streams for this OS
1706 static int os_default_xattr_streams[1] = { STREAM_XATTR_TRU64 };
1707 static const char *xattr_acl_skiplist[1] = { NULL };
1708 static const char *xattr_skiplist[1] = { NULL };
1710 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1717 int xattr_count = 0;
1720 int32_t xattr_list_len,
1723 uint32_t expected_serialize_len = 0;
1724 xattr_t *current_xattr = NULL;
1725 alist *xattr_value_list = NULL;
1726 struct proplistname_args prop_args;
1727 bxattr_exit_code retval = bxattr_exit_error;
1728 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1731 xattrbuf_size = sizeof_pool_memory(xattrbuf);
1732 xattrbuf_min_size = 0;
1733 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1734 xattrbuf, &xattrbuf_min_size);
1737 * See what xattr are available.
1739 switch (xattr_list_len) {
1744 * If the filesystem reports it doesn't support XATTRs we clear the
1745 * BXATTR_FLAG_SAVE_NATIVE flag so we skip XATTR saves on all other files
1746 * on the same filesystem. The BXATTR_FLAG_SAVE_NATIVE flags gets sets again
1747 * when we change from one filesystem to an other.
1749 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1750 retval = bxattr_exit_ok;
1753 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1754 jcr->last_fname, be.bstrerror());
1755 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1756 jcr->last_fname, be.bstrerror());
1761 if (xattrbuf_min_size) {
1763 * The buffer isn't big enough to hold the xattr data, we now have
1764 * a minimum buffersize so we resize the buffer and try again.
1766 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1767 xattrbuf_size = xattrbuf_min_size + 1;
1768 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1769 xattrbuf, &xattrbuf_min_size);
1770 switch (xattr_list_len) {
1774 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1775 jcr->last_fname, be.bstrerror());
1776 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1777 jcr->last_fname, be.bstrerror());
1783 * This should never happen as we sized the buffer according to the minimumsize
1784 * returned by a previous getproplist call. If it does happen things are fishy and
1785 * we are better of forgetting this xattr as it seems its list is changing at this
1786 * exact moment so we can never make a good backup copy of it.
1788 retval = bxattr_exit_ok;
1797 retval = bxattr_exit_ok;
1806 * Walk the list of extended attributes names and retrieve the data.
1807 * We already count the bytes needed for serializing the stream later on.
1810 while (xattrbuf_size > 0) {
1812 * Call getproplist_entry to initialize name and value
1813 * pointers to entries position within buffer.
1815 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
1818 * On some OSes you also get the acls in the extented attribute list.
1819 * So we check if we are already backing up acls and if we do we
1820 * don't store the extended attribute with the same info.
1822 if (ff_pkt->flags & FO_ACL) {
1823 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1824 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
1832 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1835 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1836 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
1844 Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
1849 * Each xattr valuepair starts with a magic so we can parse it easier.
1851 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1852 current_xattr->magic = XATTR_MAGIC;
1853 expected_serialize_len += sizeof(current_xattr->magic);
1855 current_xattr->name_length = strlen(xattr_name);
1856 current_xattr->name = bstrdup(xattr_name);
1858 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1860 current_xattr->value_length = *xattr_value_len;
1861 current_xattr->value = (char *)malloc(current_xattr->value_length);
1862 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
1864 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1867 * Protect ourself against things getting out of hand.
1869 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1870 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1871 jcr->last_fname, MAX_XATTR_STREAM);
1875 if (xattr_value_list == NULL) {
1876 xattr_value_list = New(alist(10, not_owned_by_alist));
1879 xattr_value_list->append(current_xattr);
1880 current_xattr = NULL;
1885 * If we found any xattr send them to the SD.
1887 if (xattr_count > 0) {
1889 * Serialize the datastream.
1891 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1892 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1894 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1900 * Send the datastream to the SD.
1902 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1906 if (current_xattr != NULL) {
1907 if (current_xattr->value != NULL) {
1908 free(current_xattr->value);
1910 if (current_xattr->name != NULL) {
1911 free(current_xattr->name);
1913 free(current_xattr);
1915 if (xattr_value_list != NULL) {
1916 xattr_drop_internal_table(xattr_value_list);
1918 free_pool_memory(xattrbuf);
1923 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr, int stream)
1925 char *bp, *xattrbuf = NULL;
1926 int32_t xattrbuf_size, cnt;
1927 xattr_t *current_xattr;
1928 alist *xattr_value_list;
1929 bxattr_exit_code retval = bxattr_exit_error;
1932 xattr_value_list = New(alist(10, not_owned_by_alist));
1934 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1935 xattr_drop_internal_table(xattr_value_list);
1936 return bxattr_exit_error;
1940 * See how big the propertylist must be.
1943 foreach_alist(current_xattr, xattr_value_list) {
1944 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
1947 xattrbuf = (char *)malloc(xattrbuf_size);
1950 * Add all value pairs to the proplist.
1954 foreach_alist(current_xattr, xattr_value_list) {
1955 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
1956 current_xattr->value, &bp);
1962 if (cnt != xattrbuf_size) {
1963 Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
1965 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
1971 * Restore the list of extended attributes on the file.
1973 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
1979 * If the filesystem reports it doesn't support XATTRs we clear the
1980 * BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores on all other files
1981 * on the same filesystem. The BXATTR_FLAG_RESTORE_NATIVE flags gets sets again
1982 * when we change from one filesystem to an other.
1984 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
1985 retval = bxattr_exit_ok;
1988 Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
1989 jcr->last_fname, be.bstrerror());
1990 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
1991 jcr->last_fname, be.bstrerror());
2001 xattr_drop_internal_table(xattr_value_list);
2002 return bxattr_exit_ok;
2008 xattr_drop_internal_table(xattr_value_list);
2009 return bxattr_exit_error;
2013 * Function pointers to the build and parse function to use for these xattrs.
2015 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_xattr_streams;
2016 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = tru64_parse_xattr_streams;
2018 #elif defined(HAVE_SUN_OS)
2020 * Solaris extended attributes were introduced in Solaris 9
2023 * Solaris extensible attributes were introduced in OpenSolaris
2024 * by PSARC 2007/315 Solaris extensible attributes are also
2025 * sometimes called extended system attributes.
2027 * man fsattr(5) on Solaris gives a wealth of info. The most
2028 * important bits are:
2030 * Attributes are logically supported as files within the file
2031 * system. The file system is therefore augmented with an
2032 * orthogonal name space of file attributes. Any file (includ-
2033 * ing attribute files) can have an arbitrarily deep attribute
2034 * tree associated with it. Attribute values are accessed by
2035 * file descriptors obtained through a special attribute inter-
2036 * face. This logical view of "attributes as files" allows the
2037 * leveraging of existing file system interface functionality
2038 * to support the construction, deletion, and manipulation of
2041 * The special files "." and ".." retain their accustomed
2042 * semantics within the attribute hierarchy. The "." attribute
2043 * file refers to the current directory and the ".." attribute
2044 * file refers to the parent directory. The unnamed directory
2045 * at the head of each attribute tree is considered the "child"
2046 * of the file it is associated with and the ".." file refers
2047 * to the associated file. For any non-directory file with
2048 * attributes, the ".." entry in the unnamed directory refers
2049 * to a file that is not a directory.
2051 * Conceptually, the attribute model is fully general. Extended
2052 * attributes can be any type of file (doors, links, direc-
2053 * tories, and so forth) and can even have their own attributes
2054 * (fully recursive). As a result, the attributes associated
2055 * with a file could be an arbitrarily deep directory hierarchy
2056 * where each attribute could have an equally complex attribute
2057 * tree associated with it. Not all implementations are able
2058 * to, or want to, support the full model. Implementation are
2059 * therefore permitted to reject operations that are not sup-
2060 * ported. For example, the implementation for the UFS file
2061 * system allows only regular files as attributes (for example,
2062 * no sub-directories) and rejects attempts to place attributes
2065 * The following list details the operations that are rejected
2066 * in the current implementation:
2068 * link Any attempt to create links between
2069 * attribute and non-attribute space
2070 * is rejected to prevent security-
2071 * related or otherwise sensitive
2072 * attributes from being exposed, and
2073 * therefore manipulable, as regular
2076 * rename Any attempt to rename between
2077 * attribute and non-attribute space
2078 * is rejected to prevent an already
2079 * linked file from being renamed and
2080 * thereby circumventing the link res-
2083 * mkdir, symlink, mknod Any attempt to create a "non-
2084 * regular" file in attribute space is
2085 * rejected to reduce the functional-
2086 * ity, and therefore exposure and
2087 * risk, of the initial implementa-
2090 * The entire available name space has been allocated to "gen-
2091 * eral use" to bring the implementation in line with the NFSv4
2092 * draft standard [NFSv4]. That standard defines "named attri-
2093 * butes" (equivalent to Solaris Extended Attributes) with no
2094 * naming restrictions. All Sun applications making use of
2095 * opaque extended attributes will use the prefix "SUNW".
2098 #ifdef HAVE_SYS_ATTR_H
2099 #include <sys/attr.h>
2106 #ifdef HAVE_SYS_NVPAIR_H
2107 #include <sys/nvpair.h>
2110 #ifdef HAVE_SYS_ACL_H
2111 #include <sys/acl.h>
2114 #if !defined(HAVE_OPENAT) || \
2115 !defined(HAVE_UNLINKAT) || \
2116 !defined(HAVE_FCHOWNAT) || \
2117 !defined(HAVE_FUTIMESAT)
2118 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2122 * Define the supported XATTR streams for this OS
2124 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2125 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
2127 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
2128 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2131 * This code creates a temporary cache with entries for each xattr which has
2132 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2134 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2136 xattr_link_cache_entry_t *ptr;
2138 foreach_alist(ptr, jcr->xattr_data->link_cache) {
2139 if (ptr && ptr->inum == inum) {
2146 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2148 xattr_link_cache_entry_t *ptr;
2150 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2151 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
2153 bstrncpy(ptr->target, target, sizeof(ptr->target));
2154 jcr->xattr_data->link_cache->append(ptr);
2157 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2159 * This function returns true if a non default extended system attribute
2160 * list is associated with fd and returns false when an error has occured
2161 * or when only extended system attributes other than archive,
2162 * av_modified or crtime are set.
2164 * The function returns true for the following cases:
2166 * - any extended system attribute other than the default attributes
2167 * ('archive', 'av_modified' and 'crtime') is set
2168 * - nvlist has NULL name string
2169 * - nvpair has data type of 'nvlist'
2170 * - default data type.
2172 static bool solaris_has_non_transient_extensible_attributes(int fd)
2180 bool retval = false;
2182 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2187 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2188 name = nvpair_name(pair);
2191 fattr = name_to_attr(name);
2197 type = nvpair_type(pair);
2199 case DATA_TYPE_BOOLEAN_VALUE:
2200 if (nvpair_value_boolean_value(pair, &value) != 0) {
2203 if (value && fattr != F_ARCHIVE &&
2204 fattr != F_AV_MODIFIED) {
2209 case DATA_TYPE_UINT64_ARRAY:
2210 if (fattr != F_CRTIME) {
2215 case DATA_TYPE_NVLIST:
2223 if (response != NULL) {
2224 nvlist_free(response);
2228 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2230 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2232 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2233 * There is no need to store those acls as we already store the stat bits too.
2235 static bool acl_is_trivial(int count, aclent_t *entries)
2240 for (n = 0; n < count; n++) {
2242 if (!(ace->a_type == USER_OBJ ||
2243 ace->a_type == GROUP_OBJ ||
2244 ace->a_type == OTHER_OBJ ||
2245 ace->a_type == CLASS_OBJ))
2250 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2252 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2255 #ifdef HAVE_EXTENDED_ACL
2261 * See if this attribute has an ACL
2263 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2264 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2266 * See if there is a non trivial acl on the file.
2268 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2269 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2272 return bxattr_exit_ok;
2274 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2275 attrname, jcr->last_fname, be.bstrerror());
2276 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2277 attrname, jcr->last_fname, be.bstrerror());
2278 return bxattr_exit_error;
2283 #if defined(ACL_SID_FMT)
2285 * New format flag added in newer Solaris versions.
2287 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2289 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2290 #endif /* ACL_SID_FMT */
2292 *acl_text = acl_totext(aclp, flags);
2300 return bxattr_exit_ok;
2301 #else /* HAVE_EXTENDED_ACL */
2303 aclent_t *acls = NULL;
2307 * See if this attribute has an ACL
2310 n = facl(fd, GETACLCNT, 0, NULL);
2312 n = acl(attrname, GETACLCNT, 0, NULL);
2315 if (n >= MIN_ACL_ENTRIES) {
2316 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2317 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2318 acl(attrname, GETACL, n, acls) != n) {
2322 return bxattr_exit_ok;
2324 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2325 attrname, jcr->last_fname, be.bstrerror());
2326 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2327 attrname, jcr->last_fname, be.bstrerror());
2329 return bxattr_exit_error;
2334 * See if there is a non trivial acl on the file.
2336 if (!acl_is_trivial(n, acls)) {
2337 if ((*acl_text = acltotext(acls, n)) == NULL) {
2338 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2339 attrname, jcr->last_fname, be.bstrerror());
2340 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2341 attrname, jcr->last_fname, be.bstrerror());
2343 return bxattr_exit_error;
2353 return bxattr_exit_ok;
2354 #endif /* HAVE_EXTENDED_ACL */
2356 #else /* HAVE_ACL */
2357 return bxattr_exit_ok;
2358 #endif /* HAVE_ACL */
2362 * Forward declaration for recursive function call.
2364 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2367 * Save an extended or extensible attribute.
2368 * This is stored as an opaque stream of bytes with the following encoding:
2370 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2372 * or for a hardlinked or symlinked attribute
2374 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2376 * xattr_name can be a subpath relative to the file the xattr is on.
2377 * stat_buffer is the string representation of the stat struct.
2378 * acl_string is an acl text when a non trivial acl is set on the xattr.
2379 * actual_xattr_data is the content of the xattr file.
2381 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2382 const char *attrname, bool toplevel_hidden_dir, int stream)
2387 xattr_link_cache_entry_t *xlce;
2388 char target_attrname[PATH_MAX];
2389 char link_source[PATH_MAX];
2390 char *acl_text = NULL;
2391 char attribs[MAXSTRING];
2392 char buffer[XATTR_BUFSIZ];
2393 bxattr_exit_code retval = bxattr_exit_error;
2396 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2399 * Get the stats of the extended or extensible attribute.
2401 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2404 retval = bxattr_exit_ok;
2407 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2408 target_attrname, jcr->last_fname, be.bstrerror());
2409 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2410 target_attrname, jcr->last_fname, be.bstrerror());
2416 * Based on the filetype perform the correct action. We support most filetypes here, more
2417 * then the actual implementation on Solaris supports so some code may never get executed
2418 * due to limitations in the implementation.
2420 switch (st.st_mode & S_IFMT) {
2425 * Get any acl on the xattr.
2427 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2431 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2432 * Encode the stat struct into an ASCII representation.
2434 encode_stat(attribs, &st, sizeof(st), 0, stream);
2435 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2436 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2440 * Get any acl on the xattr.
2442 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2446 * See if this is the toplevel_hidden_dir being saved.
2448 if (toplevel_hidden_dir) {
2450 * Save the data for later storage when we encounter a real xattr. We store the data
2451 * in the jcr->xattr_data->content buffer and flush that just before sending out the
2452 * first real xattr. Encode the stat struct into an ASCII representation and jump
2453 * out of the function.
2455 encode_stat(attribs, &st, sizeof(st), 0, stream);
2456 cnt = bsnprintf(buffer, sizeof(buffer),
2458 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2459 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2460 jcr->xattr_data->content_length = cnt;
2464 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2465 * Encode the stat struct into an ASCII representation.
2467 encode_stat(attribs, &st, sizeof(st), 0, stream);
2468 cnt = bsnprintf(buffer, sizeof(buffer),
2470 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2475 * If this is a hardlinked file check the inode cache for a hit.
2477 if (st.st_nlink > 1) {
2479 * See if the cache already knows this inode number.
2481 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2483 * Generate a xattr encoding with the reference to the target in there.
2485 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2486 cnt = bsnprintf(buffer, sizeof(buffer),
2488 target_attrname, 0, attribs, 0, xlce->target, 0);
2489 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2490 jcr->xattr_data->content_length = cnt;
2491 retval = send_xattr_stream(jcr, stream);
2494 * For a hard linked file we are ready now, no need to recursively save the attributes.
2500 * Store this hard linked file in the cache.
2501 * Store the name relative to the top level xattr space.
2503 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2507 * Get any acl on the xattr.
2509 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2514 * Encode the stat struct into an ASCII representation.
2516 encode_stat(attribs, &st, sizeof(st), 0, stream);
2517 cnt = bsnprintf(buffer, sizeof(buffer),
2519 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2522 * Open the extended or extensible attribute file.
2524 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2527 retval = bxattr_exit_ok;
2530 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2531 target_attrname, jcr->last_fname, be.bstrerror());
2532 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2533 target_attrname, jcr->last_fname, be.bstrerror());
2540 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2541 * Encode the stat struct into an ASCII representation.
2543 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2546 retval = bxattr_exit_ok;
2549 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2550 target_attrname, jcr->last_fname, be.bstrerror());
2551 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2552 target_attrname, jcr->last_fname, be.bstrerror());
2558 * Generate a xattr encoding with the reference to the target in there.
2560 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2561 cnt = bsnprintf(buffer, sizeof(buffer),
2563 target_attrname, 0, attribs, 0, link_source, 0);
2564 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2565 jcr->xattr_data->content_length = cnt;
2566 retval = send_xattr_stream(jcr, stream);
2568 if (retval == bxattr_exit_ok) {
2569 jcr->xattr_data->nr_saved++;
2573 * For a soft linked file we are ready now, no need to recursively save the attributes.
2581 * See if this is the first real xattr being saved.
2582 * If it is save the toplevel_hidden_dir attributes first.
2583 * This is easy as its stored already in the jcr->xattr_data->content buffer.
2585 if (jcr->xattr_data->nr_saved == 0) {
2586 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2587 if (retval != bxattr_exit_ok) {
2590 jcr->xattr_data->nr_saved++;
2593 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2594 jcr->xattr_data->content_length = cnt;
2597 * Only dump the content of regular files.
2599 switch (st.st_mode & S_IFMT) {
2601 if (st.st_size > 0) {
2603 * Protect ourself against things getting out of hand.
2605 if (st.st_size >= MAX_XATTR_STREAM) {
2606 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2607 jcr->last_fname, MAX_XATTR_STREAM);
2611 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2612 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
2613 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
2614 jcr->xattr_data->content_length += cnt;
2618 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
2619 target_attrname, jcr->last_fname);
2620 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2621 target_attrname, jcr->last_fname);
2632 retval = send_xattr_stream(jcr, stream);
2633 if (retval == bxattr_exit_ok) {
2634 jcr->xattr_data->nr_saved++;
2639 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2640 * available on this extended attribute.
2643 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2646 * The recursive call could change our working dir so change back to the wanted workdir.
2648 if (fchdir(fd) < 0) {
2651 retval = bxattr_exit_ok;
2654 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2655 jcr->last_fname, be.bstrerror());
2656 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2657 jcr->last_fname, fd, be.bstrerror());
2664 if (acl_text != NULL) {
2673 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2676 int fd, filefd = -1, attrdirfd = -1;
2679 char current_xattr_namespace[PATH_MAX];
2680 bxattr_exit_code retval = bxattr_exit_error;
2684 * Determine what argument to use. Use attr_parent when set
2685 * (recursive call) or jcr->last_fname for first call. Also save
2686 * the current depth of the xattr_space we are in.
2690 if (xattr_namespace) {
2691 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2692 xattr_namespace, attr_parent);
2694 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2697 name = jcr->last_fname;
2698 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2702 * Open the file on which to save the xattrs read-only.
2704 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2707 retval = bxattr_exit_ok;
2710 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2711 jcr->last_fname, be.bstrerror());
2712 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2713 jcr->last_fname, be.bstrerror());
2719 * Open the xattr naming space.
2721 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2725 * Gentile way of the system saying this type of xattr layering is not supported.
2726 * Which is not problem we just forget about this this xattr.
2727 * But as this is not an error we return a positive return value.
2729 retval = bxattr_exit_ok;
2732 retval = bxattr_exit_ok;
2735 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2736 name, jcr->last_fname, be.bstrerror());
2737 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2738 name, jcr->last_fname, be.bstrerror());
2744 * We need to change into the attribute directory to determine if each of the
2745 * attributes should be saved.
2747 if (fchdir(attrdirfd) < 0) {
2748 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2749 jcr->last_fname, be.bstrerror());
2750 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2751 jcr->last_fname, attrdirfd, be.bstrerror());
2756 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2757 * else because the readdir returns "." entry after the extensible attr entry.
2758 * And as we want this entry before anything else we better just save its data.
2761 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2762 true, STREAM_XATTR_SOLARIS);
2764 if ((fd = dup(attrdirfd)) == -1 ||
2765 (dirp = fdopendir(fd)) == (DIR *)NULL) {
2766 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2767 jcr->last_fname, be.bstrerror());
2768 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
2769 jcr->last_fname, fd, be.bstrerror());
2775 * Walk the namespace.
2777 while ((dp = readdir(dirp)) != NULL) {
2779 * Skip only the toplevel . dir.
2781 if (!attr_parent && bstrcmp(dp->d_name, "."))
2785 * Skip all .. directories
2787 if (bstrcmp(dp->d_name, ".."))
2790 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2791 current_xattr_namespace, dp->d_name, jcr->last_fname);
2793 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2795 * We are not interested in read-only extensible attributes.
2797 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2798 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2799 current_xattr_namespace, dp->d_name, jcr->last_fname);
2805 * We are only interested in read-write extensible attributes
2806 * when they contain non-transient values.
2808 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2810 * Determine if there are non-transient system attributes at the toplevel.
2811 * We need to provide a fd to the open file.
2813 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2814 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2815 current_xattr_namespace, dp->d_name, jcr->last_fname);
2822 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2823 false, STREAM_XATTR_SOLARIS_SYS);
2826 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2831 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2832 false, STREAM_XATTR_SOLARIS);
2836 retval = bxattr_exit_ok;
2839 if (attrdirfd != -1)
2847 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
2849 #ifdef HAVE_EXTENDED_ACL
2854 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
2855 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
2857 return bxattr_exit_error;
2860 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
2861 acl_set(attrname, aclp) != 0) {
2862 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2863 attrname, jcr->last_fname, be.bstrerror());
2864 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2865 attrname, jcr->last_fname, be.bstrerror());
2866 return bxattr_exit_error;
2872 return bxattr_exit_ok;
2874 #else /* HAVE_EXTENDED_ACL */
2876 aclent_t *acls = NULL;
2879 acls = aclfromtext(acl_text, &n);
2881 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
2882 acl(attrname, SETACL, n, acls) != 0) {
2883 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2884 attrname, jcr->last_fname, be.bstrerror());
2885 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2886 attrname, jcr->last_fname, be.bstrerror());
2887 return bxattr_exit_error;
2894 return bxattr_exit_ok;
2896 #endif /* HAVE_EXTENDED_ACL */
2899 #endif /* HAVE_ACL */
2901 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
2903 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
2904 int used_bytes, total_bytes, cnt;
2905 char *bp, *target_attrname, *attribs;
2906 char *linked_target = NULL;
2907 char *acl_text = NULL;
2911 struct timeval times[2];
2912 bxattr_exit_code retval = bxattr_exit_error;
2916 * Parse the xattr stream. First the part that is the same for all xattrs.
2919 total_bytes = jcr->xattr_data->content_length;
2922 * The name of the target xattr has a leading / we are not interested
2923 * in that so skip it when decoding the string. We always start a the /
2924 * of the xattr space anyway.
2926 target_attrname = jcr->xattr_data->content + 1;
2927 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
2928 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2934 * Open the file on which to restore the xattrs read-only.
2936 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
2937 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2938 jcr->last_fname, be.bstrerror());
2939 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2940 jcr->last_fname, be.bstrerror());
2945 * Open the xattr naming space and make it the current working dir.
2947 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2948 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
2949 jcr->last_fname, be.bstrerror());
2950 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
2951 jcr->last_fname, be.bstrerror());
2955 if (fchdir(attrdirfd) < 0) {
2956 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2957 jcr->last_fname, be.bstrerror());
2958 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2959 jcr->last_fname, attrdirfd, be.bstrerror());
2964 * Try to open the correct xattr subdir based on the target_attrname given.
2965 * e.g. check if its a subdir attrname. Each / in the string makes us go
2968 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2971 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2972 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2973 target_attrname, jcr->last_fname, be.bstrerror());
2974 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2975 target_attrname, jcr->last_fname, be.bstrerror());
2983 * Open the xattr naming space.
2985 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2986 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2987 target_attrname, jcr->last_fname, be.bstrerror());
2988 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2989 target_attrname, jcr->last_fname, be.bstrerror());
2997 * Make the xattr space our current workingdir.
2999 if (fchdir(attrdirfd) < 0) {
3000 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
3001 target_attrname, jcr->last_fname, be.bstrerror());
3002 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
3003 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
3007 target_attrname = ++bp;
3011 * Decode the attributes from the stream.
3013 decode_stat(attribs, &st, sizeof(st), &inum);
3016 * Decode the next field (acl_text).
3018 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
3019 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
3025 * Based on the filetype perform the correct action. We support most filetypes here, more
3026 * then the actual implementation on Solaris supports so some code may never get executed
3027 * due to limitations in the implementation.
3029 switch (st.st_mode & S_IFMT) {
3032 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3034 unlinkat(attrdirfd, target_attrname, 0);
3035 if (mkfifo(target_attrname, st.st_mode) < 0) {
3036 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3037 target_attrname, jcr->last_fname, be.bstrerror());
3038 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
3039 target_attrname, jcr->last_fname, be.bstrerror());
3046 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3048 unlinkat(attrdirfd, target_attrname, 0);
3049 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3050 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3051 target_attrname, jcr->last_fname, be.bstrerror());
3052 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3053 target_attrname, jcr->last_fname, be.bstrerror());
3059 * If its not the hidden_dir create the entry.
3060 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3062 if (!bstrcmp(target_attrname, ".")) {
3063 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3064 if (mkdir(target_attrname, st.st_mode) < 0) {
3065 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3066 target_attrname, jcr->last_fname, be.bstrerror());
3067 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3068 target_attrname, jcr->last_fname, be.bstrerror());
3075 * See if this is a hard linked file. e.g. inum != 0
3080 unlinkat(attrdirfd, target_attrname, 0);
3081 if (link(linked_target, target_attrname) < 0) {
3082 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3083 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3084 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3085 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3090 * Successfully restored xattr.
3092 retval = bxattr_exit_ok;
3095 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3096 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
3100 if (used_bytes < (total_bytes - 1))
3104 * Restore the actual xattr.
3106 if (!is_extensible) {
3107 unlinkat(attrdirfd, target_attrname, 0);
3110 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3111 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3112 target_attrname, jcr->last_fname, be.bstrerror());
3113 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3114 target_attrname, jcr->last_fname, be.bstrerror());
3120 * Restore the actual data.
3122 if (st.st_size > 0) {
3123 used_bytes = (data - jcr->xattr_data->content);
3124 cnt = total_bytes - used_bytes;
3127 * Do a sanity check, the st.st_size should be the same as the number of bytes
3128 * we have available as data of the stream.
3130 if (cnt != st.st_size) {
3131 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3132 target_attrname, jcr->last_fname);
3133 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3134 target_attrname, jcr->last_fname);
3139 cnt = write(attrfd, data, cnt);
3141 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3142 target_attrname, jcr->last_fname, be.bstrerror());
3143 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3144 target_attrname, jcr->last_fname, be.bstrerror());
3150 cnt = total_bytes - used_bytes;
3156 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3160 if (symlink(linked_target, target_attrname) < 0) {
3161 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3162 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3163 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3164 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3169 * Successfully restored xattr.
3171 retval = bxattr_exit_ok;
3178 * Restore owner and acl for non extensible attributes.
3180 if (!is_extensible) {
3181 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3185 * Gentile way of the system saying this type of xattr layering is not supported.
3186 * But as this is not an error we return a positive return value.
3188 retval = bxattr_exit_ok;
3191 retval = bxattr_exit_ok;
3194 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3195 target_attrname, jcr->last_fname, be.bstrerror());
3196 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3197 target_attrname, jcr->last_fname, be.bstrerror());
3204 if (acl_text && *acl_text)
3205 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3207 #endif /* HAVE_ACL */
3210 * For a non extensible attribute restore access and modification time on the xattr.
3212 if (!is_extensible) {
3213 times[0].tv_sec = st.st_atime;
3214 times[0].tv_usec = 0;
3215 times[1].tv_sec = st.st_mtime;
3216 times[1].tv_usec = 0;
3218 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3219 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3220 target_attrname, jcr->last_fname, be.bstrerror());
3221 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3222 target_attrname, jcr->last_fname, be.bstrerror());
3228 * Successfully restored xattr.
3230 retval = bxattr_exit_ok;
3234 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3236 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3243 if (attrdirfd != -1) {
3252 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3255 bxattr_exit_code retval = bxattr_exit_ok;
3258 * First see if extended attributes or extensible attributes are present.
3259 * If not just pretend things went ok.
3261 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3262 jcr->xattr_data->nr_saved = 0;
3263 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
3266 * As we change the cwd in the save function save the current cwd
3267 * for restore after return from the solaris_save_xattrs function.
3269 getcwd(cwd, sizeof(cwd));
3270 retval = solaris_save_xattrs(jcr, NULL, NULL);
3272 delete jcr->xattr_data->link_cache;
3273 jcr->xattr_data->link_cache = NULL;
3278 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
3281 bool is_extensible = false;
3282 bxattr_exit_code retval;
3285 * First make sure we can restore xattr on the filesystem.
3288 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3289 case STREAM_XATTR_SOLARIS_SYS:
3290 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3291 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
3292 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3294 return bxattr_exit_error;
3297 is_extensible = true;
3300 case STREAM_XATTR_SOLARIS:
3301 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3302 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
3303 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3305 return bxattr_exit_error;
3309 return bxattr_exit_error;
3313 * As we change the cwd in the restore function save the current cwd
3314 * for restore after return from the solaris_restore_xattrs function.
3316 getcwd(cwd, sizeof(cwd));
3317 retval = solaris_restore_xattrs(jcr, is_extensible);
3324 * Function pointers to the build and parse function to use for these xattrs.
3326 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
3327 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
3329 #endif /* defined(HAVE_SUN_OS) */
3332 * Entry points when compiled with support for XATTRs on a supported platform.
3334 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3337 * See if we are changing from one device to an other.
3338 * We save the current device we are scanning and compare
3339 * it with the current st_dev in the last stat performed on
3340 * the file we are currently storing.
3342 if (jcr->xattr_data->current_dev != ff_pkt->statp.st_dev) {
3344 * Reset the acl save flags.
3346 jcr->xattr_data->flags = 0;
3347 jcr->xattr_data->flags |= BXATTR_FLAG_SAVE_NATIVE;
3350 * Save that we started scanning a new filesystem.
3352 jcr->xattr_data->current_dev = ff_pkt->statp.st_dev;
3355 if ((jcr->xattr_data->flags & BXATTR_FLAG_SAVE_NATIVE) && os_parse_xattr_streams) {
3356 return os_build_xattr_streams(jcr, ff_pkt);
3358 return bxattr_exit_ok;
3362 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
3370 * See if we are changing from one device to an other.
3371 * We save the current device we are restoring to and compare
3372 * it with the current st_dev in the last stat performed on
3373 * the file we are currently restoring.
3375 ret = lstat(jcr->last_fname, &st);
3380 return bxattr_exit_ok;
3382 Mmsg2(jcr->errmsg, _("Unable to stat file \"%s\": ERR=%s\n"),
3383 jcr->last_fname, be.bstrerror());
3384 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
3385 jcr->last_fname, be.bstrerror());
3386 return bxattr_exit_error;
3392 if (jcr->xattr_data->current_dev != st.st_dev) {
3394 * Reset the acl save flags.
3396 jcr->xattr_data->flags = 0;
3397 jcr->xattr_data->flags |= BXATTR_FLAG_RESTORE_NATIVE;
3400 * Save that we started restoring to a new filesystem.
3402 jcr->xattr_data->current_dev = st.st_dev;
3406 * See if we are still restoring native xattr to this filesystem.
3408 if ((jcr->xattr_data->flags & BXATTR_FLAG_RESTORE_NATIVE) && os_parse_xattr_streams) {
3410 * See if we can parse this stream, and ifso give it a try.
3412 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3413 if (os_default_xattr_streams[cnt] == stream) {
3414 return os_parse_xattr_streams(jcr, stream);
3419 * Increment error count but don't log an error again for the same filesystem.
3421 jcr->xattr_data->nr_errors++;
3422 return bxattr_exit_ok;
3426 * Issue a warning and discard the message. But pretend the restore was ok.
3428 Jmsg2(jcr, M_WARNING, 0,
3429 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3430 jcr->last_fname, stream);
3431 return bxattr_exit_error;