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;
227 bxattr_exit_code retval = bxattr_exit_ok;
230 * Parse the stream and call restore_xattr_on_file for each extended attribute.
232 * Start unserializing the data. We keep on looping while we have not
233 * unserialized all bytes in the stream.
235 unser_begin(content, content_length);
236 while (unser_length(content) < content_length) {
238 * First make sure the magic is present. This way we can easily catch corruption.
239 * Any missing MAGIC is fatal we do NOT try to continue.
241 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
242 unser_uint32(current_xattr->magic);
243 if (current_xattr->magic != XATTR_MAGIC) {
245 _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
247 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
250 return bxattr_exit_error;
254 * Decode the valuepair. First decode the length of the name.
256 unser_uint32(current_xattr->name_length);
257 if (current_xattr->name_length == 0) {
259 _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
261 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
264 return bxattr_exit_error;
268 * Allocate room for the name and decode its content.
270 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
271 unser_bytes(current_xattr->name, current_xattr->name_length);
274 * The xattr_name needs to be null terminated.
276 current_xattr->name[current_xattr->name_length] = '\0';
279 * Decode the value length.
281 unser_uint32(current_xattr->value_length);
283 if (current_xattr->value_length > 0) {
285 * Allocate room for the value and decode its content.
287 current_xattr->value = (char *)malloc(current_xattr->value_length);
288 unser_bytes(current_xattr->value, current_xattr->value_length);
290 Dmsg3(100, "Restoring xattr named %s, value %*s\n",
291 current_xattr->name, current_xattr->value, current_xattr->value);
293 current_xattr->value = NULL;
294 Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
297 xattr_value_list->append(current_xattr);
300 unser_end(content, content_length);
306 * This is a supported OS, See what kind of interface we should use.
308 #if defined(HAVE_AIX_OS)
310 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
311 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
312 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
313 #error "Missing full support for the Extended Attributes (EA) functions."
319 #error "Missing sys/ea.h header file"
323 * Define the supported XATTR streams for this OS
325 static int os_default_xattr_streams[1] = {
330 * Fallback to the non l-functions when those are not available.
332 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
335 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
338 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
339 #define llistea listea
342 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
345 char *xattr_list, *bp;
346 int cnt, xattr_count = 0;
347 uint32_t name_length;
348 int32_t xattr_list_len,
350 uint32_t expected_serialize_len = 0;
351 xattr_t *current_xattr = NULL;
352 alist *xattr_value_list = NULL;
353 bxattr_exit_code retval = bxattr_exit_error;
357 * First get the length of the available list with extended attributes.
359 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
360 switch (xattr_list_len) {
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;
385 return bxattr_exit_ok;
391 * Allocate room for the extented attribute list.
393 xattr_list = (char *)malloc(xattr_list_len + 1);
394 memset(xattr_list, 0, xattr_list_len + 1);
397 * Get the actual list of extended attributes names for a file.
399 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
400 switch (xattr_list_len) {
405 retval = bxattr_exit_ok;
409 _("llistea error on file \"%s\": ERR=%s\n"),
410 jcr->last_fname, be.bstrerror());
411 Dmsg2(100, "llistea error file=%s ERR=%s\n",
412 jcr->last_fname, be.bstrerror());
419 xattr_list[xattr_list_len] = '\0';
422 * Walk the list of extended attributes names and retrieve the data.
423 * We already count the bytes needed for serializing the stream later on.
426 while ((bp - xattr_list) + 1 < xattr_list_len) {
430 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
436 name_length = strlen(bp);
437 if (skip_xattr || name_length == 0) {
438 Dmsg1(100, "Skipping xattr named %s\n", bp);
439 bp = strchr(bp, '\0') + 1;
444 * Each xattr valuepair starts with a magic so we can parse it easier.
446 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
447 current_xattr->magic = XATTR_MAGIC;
448 expected_serialize_len += sizeof(current_xattr->magic);
451 * Allocate space for storing the name.
453 current_xattr->name_length = name_length;
454 current_xattr->name = (char *)malloc(current_xattr->name_length);
455 memcpy(current_xattr->name, bp, current_xattr->name_length);
457 expected_serialize_len += sizeof(current_xattr->name_length) +
458 current_xattr->name_length;
461 * First see how long the value is for the extended attribute.
463 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
464 switch (xattr_value_len) {
469 retval = bxattr_exit_ok;
473 _("lgetea error on file \"%s\": ERR=%s\n"),
474 jcr->last_fname, be.bstrerror());
475 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
476 jcr->last_fname, be.bstrerror());
481 current_xattr->value = NULL;
482 current_xattr->value_length = 0;
483 expected_serialize_len += sizeof(current_xattr->value_length);
487 * Allocate space for storing the value.
489 current_xattr->value = (char *)malloc(xattr_value_len);
490 memset(current_xattr->value, 0, xattr_value_len);
492 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
493 if (xattr_value_len < 0) {
497 retval = bxattr_exit_ok;
501 _("lgetea error on file \"%s\": ERR=%s\n"),
502 jcr->last_fname, be.bstrerror());
503 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
504 jcr->last_fname, be.bstrerror());
509 * Store the actual length of the value.
511 current_xattr->value_length = xattr_value_len;
512 expected_serialize_len += sizeof(current_xattr->value_length) +
513 current_xattr->value_length;
516 * Protect ourself against things getting out of hand.
518 if (expected_serialize_len >= MAX_XATTR_STREAM) {
520 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
521 jcr->last_fname, MAX_XATTR_STREAM);
527 if (xattr_value_list == NULL) {
528 xattr_value_list = New(alist(10, not_owned_by_alist));
531 xattr_value_list->append(current_xattr);
532 current_xattr = NULL;
534 bp = strchr(bp, '\0') + 1;
538 xattr_list = (char *)NULL;
541 * If we found any xattr send them to the SD.
543 if (xattr_count > 0) {
545 * Serialize the datastream.
547 if (serialize_xattr_stream(jcr,
548 expected_serialize_len,
549 xattr_value_list) < expected_serialize_len) {
551 _("Failed to serialize extended attributes on file \"%s\"\n"),
553 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
559 * Send the datastream to the SD.
561 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
563 retval = bxattr_exit_ok;
567 if (current_xattr != NULL) {
568 if (current_xattr->value != NULL) {
569 free(current_xattr->value);
571 if (current_xattr->name != NULL) {
572 free(current_xattr->name);
576 if (xattr_list != NULL) {
579 if (xattr_value_list != NULL) {
580 xattr_drop_internal_table(xattr_value_list);
585 static bxattr_exit_code aix_parse_xattr_streams(JCR *jcr,
588 uint32_t content_length)
590 xattr_t *current_xattr;
591 alist *xattr_value_list;
594 xattr_value_list = New(alist(10, not_owned_by_alist));
596 if (unserialize_xattr_stream(jcr,
599 xattr_value_list) != bxattr_exit_ok) {
600 xattr_drop_internal_table(xattr_value_list);
601 return bxattr_exit_error;
604 foreach_alist(current_xattr, xattr_value_list) {
605 if (lsetea(jcr->last_fname,
607 current_xattr->value,
608 current_xattr->value_length, 0) != 0) {
615 * If the filesystem reports it doesn't support XATTRs we clear
616 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
617 * on all other files on the same filesystem. The
618 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
619 * change from one filesystem to an other.
621 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
625 _("lsetea error on file \"%s\": ERR=%s\n"),
626 jcr->last_fname, be.bstrerror());
627 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
628 jcr->last_fname, be.bstrerror());
634 xattr_drop_internal_table(xattr_value_list);
635 return bxattr_exit_ok;
638 xattr_drop_internal_table(xattr_value_list);
639 return bxattr_exit_error;
643 * Function pointers to the build and parse function to use for these xattrs.
645 static bxattr_exit_code (*os_build_xattr_streams)
646 (JCR *jcr, FF_PKT *ff_pkt) =
647 aix_xattr_build_streams;
648 static bxattr_exit_code (*os_parse_xattr_streams)
649 (JCR *jcr, int stream, char *content, uint32_t content_length) =
650 aix_parse_xattr_streams;
652 #elif defined(HAVE_IRIX_OS)
654 #include <sys/attributes.h>
657 * Define the supported XATTR streams for this OS
659 static int os_default_xattr_streams[1] = {
662 static const char *xattr_acl_skiplist[1] = {
665 static const char *xattr_skiplist[1] = {
669 struct xattr_naming_space {
674 static xattr_naming_space xattr_naming_spaces[] = {
680 ATTR_ROOT | ATTR_DONTFOLLOW
687 static bxattr_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
689 int cnt, length, xattr_count = 0;
690 attrlist_cursor_t cursor;
691 attrlist_t *attrlist;
692 attrlist_ent_t *attrlist_ent;
693 xattr_t *current_xattr = NULL;
694 alist *xattr_value_list = NULL;
695 uint32_t expected_serialize_len = 0;
696 bxattr_exit_code retval = bxattr_exit_error;
697 POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
700 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
701 memset(&cursor, 0, sizeof(attrlist_cursor_t));
703 if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
704 xattr_naming_spaces[cnt].flags, &cursor) != 0) {
707 retval = bxattr_exit_ok;
711 _("attr_list error on file \"%s\": ERR=%s\n"),
712 jcr->last_fname, be.bstrerror());
713 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
714 jcr->last_fname, be.bstrerror());
719 attrlist = (attrlist_t *)xattrbuf;
722 * Walk the available attributes.
724 for (cnt = 0; cnt < attrlist->al_count; cnt++) {
725 attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
728 * Each xattr valuepair starts with a magic so we can parse it easier.
730 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
731 current_xattr->magic = XATTR_MAGIC;
732 expected_serialize_len += sizeof(current_xattr->magic);
735 * Allocate space for storing the name.
736 * We store the name as <naming_space_name><xattr_name>
738 current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) +
739 strlen(attrlist_ent->a_name) + 1;
740 current_xattr->name = (char *)malloc(current_xattr->name_length);
741 bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
742 xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
744 expected_serialize_len += sizeof(current_xattr->name_length) +
745 current_xattr->name_length;
747 current_xattr->value_length = attrlist_ent->a_valuelen;
748 current_xattr->value = (char *)malloc(current_xattr->value_length);
751 * Retrieve the actual value of the xattr.
753 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
754 &length, xattr_naming_spaces[cnt].flags) != 0) {
758 retval = bxattr_exit_ok;
762 * The buffer for the xattr isn't big enough. the value of
763 * current_xattr->value_length is updated with the actual size
764 * of the xattr. So we free the old buffer and create a new one
767 free(current_xattr->value);
768 current_xattr->value = (char *)malloc(current_xattr->value_length);
769 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
770 &length, xattr_naming_spaces[cnt].flags) != 0) {
774 retval = bxattr_exit_ok;
778 _("attr_list error on file \"%s\": ERR=%s\n"),
779 jcr->last_fname, be.bstrerror());
780 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
781 jcr->last_fname, be.bstrerror());
785 current_xattr->value_length = length;
790 _("attr_list error on file \"%s\": ERR=%s\n"),
791 jcr->last_fname, be.bstrerror());
792 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
793 jcr->last_fname, be.bstrerror());
797 current_xattr->value_length = length;
800 expected_serialize_len += sizeof(current_xattr->value_length) +
801 current_xattr->value_length;
804 * Protect ourself against things getting out of hand.
806 if (expected_serialize_len >= MAX_XATTR_STREAM) {
808 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
809 jcr->last_fname, MAX_XATTR_STREAM);
813 if (xattr_value_list == NULL) {
814 xattr_value_list = New(alist(10, not_owned_by_alist));
817 xattr_value_list->append(current_xattr);
818 current_xattr = NULL;
823 * See if there are more attributes available for a next run of attr_list.
825 if (attrlist->al_more == 0) {
832 * If we found any xattr send them to the SD.
834 if (xattr_count > 0) {
836 * Serialize the datastream.
838 if (serialize_xattr_stream(jcr,
839 expected_serialize_len,
840 xattr_value_list) < expected_serialize_len) {
842 _("Failed to serialize extended attributes on file \"%s\"\n"),
844 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
850 * Send the datastream to the SD.
852 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
854 retval = bxattr_exit_ok;
858 if (current_xattr != NULL) {
859 if (current_xattr->value != NULL) {
860 free(current_xattr->value);
862 if (current_xattr->name != NULL) {
863 free(current_xattr->name);
867 free_pool_memory(xattrbuf);
869 if (xattr_value_list != NULL) {
870 xattr_drop_internal_table(xattr_value_list);
875 static bxattr_exit_code irix_parse_xattr_streams(JCR *jcr,
878 uint32_t content_length)
881 int cnt, cmp_size, name_space_index, flags;
882 xattr_t *current_xattr;
883 alist *xattr_value_list;
884 bxattr_exit_code retval = bxattr_exit_error;
887 xattr_value_list = New(alist(10, not_owned_by_alist));
889 if (unserialize_xattr_stream(jcr,
892 xattr_value_list) != bxattr_exit_ok) {
893 xattr_drop_internal_table(xattr_value_list);
894 return bxattr_exit_error;
897 foreach_alist(current_xattr, xattr_value_list) {
899 * See to what namingspace this xattr belongs to.
901 name_space_index = 0;
902 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
903 cmp_size = strlen(xattr_naming_spaces[cnt].name);
904 if (!strncasecmp(current_xattr->name,
905 xattr_naming_spaces[cnt].name,
907 name_space_index = cnt;
913 * If we got a xattr that doesn't belong to an valid namespace complain.
915 if (name_space_index == 0) {
917 _("Received illegal xattr named %s on file \"%s\"\n"),
918 current_xattr->name, jcr->last_fname);
919 Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
920 current_xattr->name, jcr->last_fname);
925 * Restore the xattr first try to create the attribute from scratch.
927 flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
928 bp = strchr(current_xattr->name, '.');
929 if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
930 current_xattr->value_length, flags) != 0) {
933 retval = bxattr_exit_ok;
937 * The xattr already exists we need to replace it.
939 flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
940 if (attr_set(jcr->last_fname, bp, current_xattr->value,
941 current_xattr->value_length, flags) != 0) {
944 retval = bxattr_exit_ok;
948 _("attr_set error on file \"%s\": ERR=%s\n"),
949 jcr->last_fname, be.bstrerror());
950 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
951 jcr->last_fname, be.bstrerror());
958 _("attr_set error on file \"%s\": ERR=%s\n"),
959 jcr->last_fname, be.bstrerror());
960 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
961 jcr->last_fname, be.bstrerror());
967 xattr_drop_internal_table(xattr_value_list);
968 return bxattr_exit_ok;
971 xattr_drop_internal_table(xattr_value_list);
972 return bxattr_exit_error;
976 * Function pointers to the build and parse function to use for these xattrs.
978 static bxattr_exit_code (*os_build_xattr_streams)
979 (JCR *jcr, FF_PKT *ff_pkt) =
980 irix_xattr_build_streams;
981 static bxattr_exit_code (*os_parse_xattr_streams)
982 (JCR *jcr, int stream, char *content, uint32_t content_length) =
983 irix_parse_xattr_streams;
985 #elif defined(HAVE_DARWIN_OS) || \
986 defined(HAVE_LINUX_OS)
988 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
989 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
990 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
991 #error "Missing full support for the XATTR functions."
994 #ifdef HAVE_SYS_XATTR_H
995 #include <sys/xattr.h>
997 #error "Missing sys/xattr.h header file"
1001 * Define the supported XATTR streams for this OS
1003 #if defined(HAVE_DARWIN_OS)
1004 static int os_default_xattr_streams[1] = {
1007 static const char *xattr_acl_skiplist[2] = {
1008 "com.apple.system.Security",
1011 static const char *xattr_skiplist[3] = {
1012 "com.apple.system.extendedsecurity",
1013 "com.apple.ResourceFork",
1016 #elif defined(HAVE_LINUX_OS)
1017 static int os_default_xattr_streams[1] = {
1020 static const char *xattr_acl_skiplist[3] = {
1021 "system.posix_acl_access",
1022 "system.posix_acl_default",
1025 static const char *xattr_skiplist[1] = {
1031 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
1032 * listxattr, getxattr and setxattr with an extra options argument
1033 * which mimics the l variants of the functions when we specify
1034 * XATTR_NOFOLLOW as the options value.
1036 #if defined(HAVE_DARWIN_OS)
1037 #define llistxattr(path, list, size) \
1038 listxattr((path), (list), (size), XATTR_NOFOLLOW)
1039 #define lgetxattr(path, name, value, size) \
1040 getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
1041 #define lsetxattr(path, name, value, size, flags) \
1042 setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
1045 * Fallback to the non l-functions when those are not available.
1047 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
1048 #define lgetxattr getxattr
1050 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
1051 #define lsetxattr setxattr
1053 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
1054 #define llistxattr listxattr
1058 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
1061 char *xattr_list, *bp;
1062 int cnt, xattr_count = 0;
1063 uint32_t name_length;
1064 int32_t xattr_list_len,
1066 uint32_t expected_serialize_len = 0;
1067 xattr_t *current_xattr = NULL;
1068 alist *xattr_value_list = NULL;
1069 bxattr_exit_code retval = bxattr_exit_error;
1073 * First get the length of the available list with extended attributes.
1075 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
1076 switch (xattr_list_len) {
1080 return bxattr_exit_ok;
1081 case BXATTR_ENOTSUP:
1083 * If the filesystem reports it doesn't support XATTRs we clear
1084 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1085 * on all other files on the same filesystem. The
1086 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1087 * change from one filesystem to an other.
1089 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1090 return bxattr_exit_ok;
1093 _("llistxattr error on file \"%s\": ERR=%s\n"),
1094 jcr->last_fname, be.bstrerror());
1095 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1096 jcr->last_fname, be.bstrerror());
1097 return bxattr_exit_error;
1101 return bxattr_exit_ok;
1107 * Allocate room for the extented attribute list.
1109 xattr_list = (char *)malloc(xattr_list_len + 1);
1110 memset(xattr_list, 0, xattr_list_len + 1);
1113 * Get the actual list of extended attributes names for a file.
1115 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
1116 switch (xattr_list_len) {
1120 retval = bxattr_exit_ok;
1124 _("llistxattr error on file \"%s\": ERR=%s\n"),
1125 jcr->last_fname, be.bstrerror());
1126 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1127 jcr->last_fname, be.bstrerror());
1134 xattr_list[xattr_list_len] = '\0';
1137 * Walk the list of extended attributes names and retrieve the data.
1138 * We already count the bytes needed for serializing the stream later on.
1141 while ((bp - xattr_list) + 1 < xattr_list_len) {
1145 * On some OSes you also get the acls in the extented attribute list.
1146 * So we check if we are already backing up acls and if we do we
1147 * don't store the extended attribute with the same info.
1149 if (ff_pkt->flags & FO_ACL) {
1150 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1151 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1159 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1162 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1163 if (bstrcmp(bp, xattr_skiplist[cnt])) {
1170 name_length = strlen(bp);
1171 if (skip_xattr || name_length == 0) {
1172 Dmsg1(100, "Skipping xattr named %s\n", bp);
1173 bp = strchr(bp, '\0') + 1;
1178 * Each xattr valuepair starts with a magic so we can parse it easier.
1180 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1181 current_xattr->magic = XATTR_MAGIC;
1182 expected_serialize_len += sizeof(current_xattr->magic);
1185 * Allocate space for storing the name.
1187 current_xattr->name_length = name_length;
1188 current_xattr->name = (char *)malloc(current_xattr->name_length);
1189 memcpy(current_xattr->name, bp, current_xattr->name_length);
1191 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1194 * First see how long the value is for the extended attribute.
1196 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1197 switch (xattr_value_len) {
1201 retval = bxattr_exit_ok;
1205 _("lgetxattr error on file \"%s\": ERR=%s\n"),
1206 jcr->last_fname, be.bstrerror());
1207 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1208 jcr->last_fname, be.bstrerror());
1213 current_xattr->value = NULL;
1214 current_xattr->value_length = 0;
1215 expected_serialize_len += sizeof(current_xattr->value_length);
1219 * Allocate space for storing the value.
1221 current_xattr->value = (char *)malloc(xattr_value_len);
1222 memset(current_xattr->value, 0, xattr_value_len);
1224 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1225 if (xattr_value_len < 0) {
1228 retval = bxattr_exit_ok;
1232 _("lgetxattr error on file \"%s\": ERR=%s\n"),
1233 jcr->last_fname, be.bstrerror());
1234 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1235 jcr->last_fname, be.bstrerror());
1240 * Store the actual length of the value.
1242 current_xattr->value_length = xattr_value_len;
1243 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1246 * Protect ourself against things getting out of hand.
1248 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1250 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1251 jcr->last_fname, MAX_XATTR_STREAM);
1256 if (xattr_value_list == NULL) {
1257 xattr_value_list = New(alist(10, not_owned_by_alist));
1260 xattr_value_list->append(current_xattr);
1261 current_xattr = NULL;
1263 bp = strchr(bp, '\0') + 1;
1268 xattr_list = (char *)NULL;
1271 * If we found any xattr send them to the SD.
1273 if (xattr_count > 0) {
1275 * Serialize the datastream.
1277 if (serialize_xattr_stream(jcr,
1278 expected_serialize_len,
1279 xattr_value_list) < expected_serialize_len) {
1281 _("Failed to serialize extended attributes on file \"%s\"\n"),
1283 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1289 * Send the datastream to the SD.
1291 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1293 retval = bxattr_exit_ok;
1297 if (current_xattr != NULL) {
1298 if (current_xattr->value != NULL) {
1299 free(current_xattr->value);
1301 if (current_xattr->name != NULL) {
1302 free(current_xattr->name);
1304 free(current_xattr);
1306 if (xattr_list != NULL) {
1309 if (xattr_value_list != NULL) {
1310 xattr_drop_internal_table(xattr_value_list);
1315 static bxattr_exit_code generic_parse_xattr_streams(JCR *jcr,
1318 uint32_t content_length)
1320 xattr_t *current_xattr;
1321 alist *xattr_value_list;
1324 xattr_value_list = New(alist(10, not_owned_by_alist));
1326 if (unserialize_xattr_stream(jcr,
1329 xattr_value_list) != bxattr_exit_ok) {
1330 xattr_drop_internal_table(xattr_value_list);
1331 return bxattr_exit_error;
1334 foreach_alist(current_xattr, xattr_value_list) {
1335 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1339 case BXATTR_ENOTSUP:
1341 * If the filesystem reports it doesn't support XATTRs we clear
1342 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1343 * on all other files on the same filesystem. The
1344 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1345 * change from one filesystem to an other.
1347 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
1351 _("lsetxattr error on file \"%s\": ERR=%s\n"),
1352 jcr->last_fname, be.bstrerror());
1353 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1354 jcr->last_fname, be.bstrerror());
1360 xattr_drop_internal_table(xattr_value_list);
1361 return bxattr_exit_ok;
1364 xattr_drop_internal_table(xattr_value_list);
1365 return bxattr_exit_error;
1369 * Function pointers to the build and parse function to use for these xattrs.
1371 static bxattr_exit_code (*os_build_xattr_streams)
1372 (JCR *jcr, FF_PKT *ff_pkt) =
1373 generic_xattr_build_streams;
1374 static bxattr_exit_code (*os_parse_xattr_streams)
1375 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1376 generic_parse_xattr_streams;
1378 #elif defined(HAVE_FREEBSD_OS) || \
1379 defined(HAVE_NETBSD_OS) || \
1380 defined(HAVE_OPENBSD_OS)
1382 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1383 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1384 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1385 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1386 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1387 #error "Missing full support for the extattr functions."
1390 #ifdef HAVE_SYS_EXTATTR_H
1391 #include <sys/extattr.h>
1393 #error "Missing sys/extattr.h header file"
1396 #ifdef HAVE_LIBUTIL_H
1397 #include <libutil.h>
1400 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1401 #define extattr_get_link extattr_get_file
1403 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1404 #define extattr_set_link extattr_set_file
1406 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1407 #define extattr_list_link extattr_list_file
1410 #if defined(HAVE_FREEBSD_OS)
1411 static int os_default_xattr_streams[1] = {
1412 STREAM_XATTR_FREEBSD
1414 static int os_default_xattr_namespaces[2] = {
1415 EXTATTR_NAMESPACE_USER,
1416 EXTATTR_NAMESPACE_SYSTEM
1418 static const char *xattr_acl_skiplist[4] = {
1419 "system.posix1e.acl_access",
1420 "system.posix1e.acl_default",
1424 static const char *xattr_skiplist[1] = {
1427 #elif defined(HAVE_NETBSD_OS)
1428 static int os_default_xattr_streams[1] = {
1431 static int os_default_xattr_namespaces[2] = {
1432 EXTATTR_NAMESPACE_USER,
1433 EXTATTR_NAMESPACE_SYSTEM
1435 static const char *xattr_acl_skiplist[1] = {
1438 static const char *xattr_skiplist[1] = {
1441 #elif defined(HAVE_OPENBSD_OS)
1442 static int os_default_xattr_streams[1] = {
1443 STREAM_XATTR_OPENBSD
1445 static int os_default_xattr_namespaces[2] = {
1446 EXTATTR_NAMESPACE_USER,
1447 EXTATTR_NAMESPACE_SYSTEM
1449 static const char *xattr_acl_skiplist[1] = {
1452 static const char *xattr_skiplist[1] = {
1457 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1461 int cnt, index, xattr_count = 0;
1462 int32_t xattr_list_len,
1464 uint32_t expected_serialize_len = 0;
1465 unsigned int namespace_index;
1467 char *current_attrnamespace = NULL;
1468 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1469 xattr_t *current_xattr = NULL;
1470 alist *xattr_value_list = NULL;
1471 bxattr_exit_code retval = bxattr_exit_error;
1475 * Loop over all available xattr namespaces.
1477 for (namespace_index = 0;
1478 namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int);
1479 namespace_index++) {
1480 attrnamespace = os_default_xattr_namespaces[namespace_index];
1483 * First get the length of the available list with extended attributes.
1484 * If we get EPERM on system namespace, don't return error.
1485 * This is expected for normal users trying to archive the system
1486 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1487 * they've decided to return EOPNOTSUPP instead.
1489 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1490 switch (xattr_list_len) {
1494 retval = bxattr_exit_ok;
1496 #if defined(EOPNOTSUPP)
1500 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1508 _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1509 jcr->last_fname, be.bstrerror());
1510 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1511 jcr->last_fname, be.bstrerror());
1522 * Allocate room for the extented attribute list.
1524 xattr_list = (char *)malloc(xattr_list_len + 1);
1525 memset(xattr_list, 0, xattr_list_len + 1);
1528 * Get the actual list of extended attributes names for a file.
1530 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace,
1531 xattr_list, xattr_list_len);
1532 switch (xattr_list_len) {
1536 retval = bxattr_exit_ok;
1540 _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1541 jcr->last_fname, be.bstrerror());
1542 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1543 jcr->last_fname, be.bstrerror());
1550 xattr_list[xattr_list_len] = '\0';
1553 * Convert the numeric attrnamespace into a string representation and make
1554 * a private copy of that string. The extattr_namespace_to_string functions
1555 * returns a strdupped string which we need to free.
1557 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1559 _("Failed to convert %d into namespace on file \"%s\"\n"),
1560 attrnamespace, jcr->last_fname);
1561 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1562 attrnamespace, jcr->last_fname);
1567 * Walk the list of extended attributes names and retrieve the data.
1568 * We already count the bytes needed for serializing the stream later on.
1570 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1574 * Print the current name into the buffer as its not null terminated
1575 * we need to use the length encoded in the string for copying only
1578 cnt = xattr_list[index];
1579 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1580 cnt = ((int)sizeof(current_attrname) - 1);
1582 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1583 current_attrname[cnt] = '\0';
1586 * First make a xattr tuple of the current namespace and the name of
1587 * the xattr. e.g. something like user.<attrname> or system.<attrname>
1589 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s",
1590 current_attrnamespace, current_attrname);
1593 * On some OSes you also get the acls in the extented attribute list.
1594 * So we check if we are already backing up acls and if we do we
1595 * don't store the extended attribute with the same info.
1597 if (ff_pkt->flags & FO_ACL) {
1598 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1599 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1607 * On some OSes we want to skip certain xattrs which are in the
1608 * xattr_skiplist array.
1611 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1612 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1620 Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1625 * Each xattr valuepair starts with a magic so we can parse it easier.
1627 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1628 current_xattr->magic = XATTR_MAGIC;
1629 expected_serialize_len += sizeof(current_xattr->magic);
1632 * Allocate space for storing the name.
1634 current_xattr->name_length = strlen(current_attrtuple);
1635 current_xattr->name = (char *)malloc(current_xattr->name_length);
1636 memcpy(current_xattr->name, current_attrtuple, current_xattr->name_length);
1638 expected_serialize_len += sizeof(current_xattr->name_length) +
1639 current_xattr->name_length;
1642 * First see how long the value is for the extended attribute.
1644 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1645 current_attrname, NULL, 0);
1646 switch (xattr_value_len) {
1650 retval = bxattr_exit_ok;
1654 _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1655 jcr->last_fname, be.bstrerror());
1656 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1657 jcr->last_fname, be.bstrerror());
1662 current_xattr->value = NULL;
1663 current_xattr->value_length = 0;
1664 expected_serialize_len += sizeof(current_xattr->value_length);
1668 * Allocate space for storing the value.
1670 current_xattr->value = (char *)malloc(xattr_value_len);
1671 memset(current_xattr->value, 0, xattr_value_len);
1673 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
1674 current_attrname, current_xattr->value,
1676 if (xattr_value_len < 0) {
1679 retval = bxattr_exit_ok;
1683 _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1684 jcr->last_fname, be.bstrerror());
1685 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1686 jcr->last_fname, be.bstrerror());
1692 * Store the actual length of the value.
1694 current_xattr->value_length = xattr_value_len;
1695 expected_serialize_len += sizeof(current_xattr->value_length) +
1696 current_xattr->value_length;
1699 * Protect ourself against things getting out of hand.
1701 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1703 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1704 jcr->last_fname, MAX_XATTR_STREAM);
1710 if (xattr_value_list == NULL) {
1711 xattr_value_list = New(alist(10, not_owned_by_alist));
1714 xattr_value_list->append(current_xattr);
1715 current_xattr = NULL;
1721 * Drop the local copy of the current_attrnamespace.
1723 actuallyfree(current_attrnamespace);
1724 current_attrnamespace = NULL;
1727 * We are done with this xattr list.
1730 xattr_list = (char *)NULL;
1734 * If we found any xattr send them to the SD.
1736 if (xattr_count > 0) {
1738 * Serialize the datastream.
1740 if (serialize_xattr_stream(jcr,
1741 expected_serialize_len,
1742 xattr_value_list) < expected_serialize_len) {
1744 _("Failed to serialize extended attributes on file \"%s\"\n"),
1746 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1752 * Send the datastream to the SD.
1754 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1756 retval = bxattr_exit_ok;
1760 if (current_attrnamespace != NULL) {
1761 actuallyfree(current_attrnamespace);
1763 if (current_xattr != NULL) {
1764 if (current_xattr->value != NULL) {
1765 free(current_xattr->value);
1767 if (current_xattr->name != NULL) {
1768 free(current_xattr->name);
1770 free(current_xattr);
1772 if (xattr_list != NULL) {
1775 if (xattr_value_list != NULL) {
1776 xattr_drop_internal_table(xattr_value_list);
1781 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr,
1784 uint32_t content_length)
1786 xattr_t *current_xattr;
1787 alist *xattr_value_list;
1788 int current_attrnamespace, cnt;
1789 char *attrnamespace, *attrname;
1792 xattr_value_list = New(alist(10, not_owned_by_alist));
1794 if (unserialize_xattr_stream(jcr,
1797 xattr_value_list) != bxattr_exit_ok) {
1798 xattr_drop_internal_table(xattr_value_list);
1799 return bxattr_exit_error;
1802 foreach_alist(current_xattr, xattr_value_list) {
1804 * Try splitting the xattr_name into a namespace and name part.
1805 * The splitting character is a .
1807 attrnamespace = current_xattr->name;
1808 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1810 _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1811 current_xattr->name, jcr->last_fname);
1812 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1813 current_xattr->name, jcr->last_fname);
1819 * Make sure the attrnamespace makes sense.
1821 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1823 _("Failed to convert %s into namespace on file \"%s\"\n"),
1824 attrnamespace, jcr->last_fname);
1825 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1826 attrnamespace, jcr->last_fname);
1831 * Try restoring the extended attribute.
1833 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1834 attrname, current_xattr->value, current_xattr->value_length);
1835 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1842 _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1843 jcr->last_fname, be.bstrerror());
1844 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1845 jcr->last_fname, be.bstrerror());
1852 xattr_drop_internal_table(xattr_value_list);
1853 return bxattr_exit_ok;
1856 xattr_drop_internal_table(xattr_value_list);
1857 return bxattr_exit_error;
1861 * Function pointers to the build and parse function to use for these xattrs.
1863 static bxattr_exit_code (*os_build_xattr_streams)
1864 (JCR *jcr, FF_PKT *ff_pkt) =
1865 bsd_build_xattr_streams;
1866 static bxattr_exit_code (*os_parse_xattr_streams)
1867 (JCR *jcr, int stream, char *content, uint32_t content_length) =
1868 bsd_parse_xattr_streams;
1870 #elif defined(HAVE_OSF1_OS)
1872 #if !defined(HAVE_GETPROPLIST) || \
1873 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1874 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1875 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1876 !defined(HAVE_SETPROPLIST)
1877 #error "Missing full support for the Extended Attributes functions."
1880 #ifdef HAVE_SYS_PROPLIST_H
1881 #include <sys/proplist.h>
1883 #error "Missing sys/proplist.h header file"
1887 * Define the supported XATTR streams for this OS
1889 static int os_default_xattr_streams[1] = {
1892 static const char *xattr_acl_skiplist[1] = {
1895 static const char *xattr_skiplist[1] = {
1899 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1906 int xattr_count = 0;
1909 int32_t xattr_list_len,
1912 uint32_t expected_serialize_len = 0;
1913 xattr_t *current_xattr = NULL;
1914 alist *xattr_value_list = NULL;
1915 struct proplistname_args prop_args;
1916 bxattr_exit_code retval = bxattr_exit_error;
1917 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1920 xattrbuf_size = sizeof_pool_memory(xattrbuf);
1921 xattrbuf_min_size = 0;
1922 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1923 xattrbuf, &xattrbuf_min_size);
1926 * See what xattr are available.
1928 switch (xattr_list_len) {
1933 * If the filesystem reports it doesn't support XATTRs we clear
1934 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
1935 * on all other files on the same filesystem. The
1936 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
1937 * change from one filesystem to an other.
1939 jcr->xattr_data->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
1940 retval = bxattr_exit_ok;
1944 _("getproplist error on file \"%s\": ERR=%s\n"),
1945 jcr->last_fname, be.bstrerror());
1946 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1947 jcr->last_fname, be.bstrerror());
1952 if (xattrbuf_min_size) {
1954 * The buffer isn't big enough to hold the xattr data, we now have
1955 * a minimum buffersize so we resize the buffer and try again.
1957 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1958 xattrbuf_size = xattrbuf_min_size + 1;
1959 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1960 xattrbuf, &xattrbuf_min_size);
1961 switch (xattr_list_len) {
1966 _("getproplist error on file \"%s\": ERR=%s\n"),
1967 jcr->last_fname, be.bstrerror());
1968 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1969 jcr->last_fname, be.bstrerror());
1975 * This should never happen as we sized the buffer according to the minimumsize
1976 * returned by a previous getproplist call. If it does happen things are fishy and
1977 * we are better of forgetting this xattr as it seems its list is changing at this
1978 * exact moment so we can never make a good backup copy of it.
1980 retval = bxattr_exit_ok;
1989 retval = bxattr_exit_ok;
1998 * Walk the list of extended attributes names and retrieve the data.
1999 * We already count the bytes needed for serializing the stream later on.
2002 while (xattrbuf_size > 0) {
2004 * Call getproplist_entry to initialize name and value
2005 * pointers to entries position within buffer.
2007 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
2010 * On some OSes you also get the acls in the extented attribute list.
2011 * So we check if we are already backing up acls and if we do we
2012 * don't store the extended attribute with the same info.
2014 if (ff_pkt->flags & FO_ACL) {
2015 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
2016 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
2024 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
2027 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
2028 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
2036 Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
2041 * Each xattr valuepair starts with a magic so we can parse it easier.
2043 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
2044 current_xattr->magic = XATTR_MAGIC;
2045 expected_serialize_len += sizeof(current_xattr->magic);
2047 current_xattr->name_length = strlen(xattr_name);
2048 current_xattr->name = bstrdup(xattr_name);
2050 expected_serialize_len += sizeof(current_xattr->name_length) +
2051 current_xattr->name_length;
2053 current_xattr->value_length = *xattr_value_len;
2054 current_xattr->value = (char *)malloc(current_xattr->value_length);
2055 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
2057 expected_serialize_len += sizeof(current_xattr->value_length) +
2058 current_xattr->value_length;
2061 * Protect ourself against things getting out of hand.
2063 if (expected_serialize_len >= MAX_XATTR_STREAM) {
2065 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2066 jcr->last_fname, MAX_XATTR_STREAM);
2070 if (xattr_value_list == NULL) {
2071 xattr_value_list = New(alist(10, not_owned_by_alist));
2074 xattr_value_list->append(current_xattr);
2075 current_xattr = NULL;
2080 * If we found any xattr send them to the SD.
2082 if (xattr_count > 0) {
2084 * Serialize the datastream.
2086 if (serialize_xattr_stream(jcr,
2087 expected_serialize_len,
2088 xattr_value_list) < expected_serialize_len) {
2090 _("Failed to serialize extended attributes on file \"%s\"\n"),
2092 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
2098 * Send the datastream to the SD.
2100 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
2104 if (current_xattr != NULL) {
2105 if (current_xattr->value != NULL) {
2106 free(current_xattr->value);
2108 if (current_xattr->name != NULL) {
2109 free(current_xattr->name);
2111 free(current_xattr);
2113 if (xattr_value_list != NULL) {
2114 xattr_drop_internal_table(xattr_value_list);
2116 free_pool_memory(xattrbuf);
2121 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr,
2124 uint32_t content_length)
2126 char *bp, *xattrbuf = NULL;
2127 int32_t xattrbuf_size, cnt;
2128 xattr_t *current_xattr;
2129 alist *xattr_value_list;
2130 bxattr_exit_code retval = bxattr_exit_error;
2133 xattr_value_list = New(alist(10, not_owned_by_alist));
2135 if (unserialize_xattr_stream(jcr,
2138 xattr_value_list) != bxattr_exit_ok) {
2139 xattr_drop_internal_table(xattr_value_list);
2140 return bxattr_exit_error;
2144 * See how big the propertylist must be.
2147 foreach_alist(current_xattr, xattr_value_list) {
2148 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
2151 xattrbuf = (char *)malloc(xattrbuf_size);
2154 * Add all value pairs to the proplist.
2158 foreach_alist(current_xattr, xattr_value_list) {
2159 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
2160 current_xattr->value, &bp);
2166 if (cnt != xattrbuf_size) {
2168 _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
2170 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
2176 * Restore the list of extended attributes on the file.
2178 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
2184 * If the filesystem reports it doesn't support XATTRs we clear
2185 * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
2186 * on all other files on the same filesystem. The
2187 * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
2188 * change from one filesystem to an other.
2190 jcr->xattr_data->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
2191 retval = bxattr_exit_ok;
2195 _("setproplist error on file \"%s\": ERR=%s\n"),
2196 jcr->last_fname, be.bstrerror());
2197 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
2198 jcr->last_fname, be.bstrerror());
2208 xattr_drop_internal_table(xattr_value_list);
2209 return bxattr_exit_ok;
2215 xattr_drop_internal_table(xattr_value_list);
2216 return bxattr_exit_error;
2220 * Function pointers to the build and parse function to use for these xattrs.
2222 static bxattr_exit_code (*os_build_xattr_streams)
2223 (JCR *jcr, FF_PKT *ff_pkt) =
2224 tru64_build_xattr_streams;
2225 static bxattr_exit_code (*os_parse_xattr_streams)
2226 (JCR *jcr, int stream, char *content, uint32_t content_length) =
2227 tru64_parse_xattr_streams;
2229 #elif defined(HAVE_SUN_OS)
2231 * Solaris extended attributes were introduced in Solaris 9
2234 * Solaris extensible attributes were introduced in OpenSolaris
2235 * by PSARC 2007/315 Solaris extensible attributes are also
2236 * sometimes called extended system attributes.
2238 * man fsattr(5) on Solaris gives a wealth of info. The most
2239 * important bits are:
2241 * Attributes are logically supported as files within the file
2242 * system. The file system is therefore augmented with an
2243 * orthogonal name space of file attributes. Any file (includ-
2244 * ing attribute files) can have an arbitrarily deep attribute
2245 * tree associated with it. Attribute values are accessed by
2246 * file descriptors obtained through a special attribute inter-
2247 * face. This logical view of "attributes as files" allows the
2248 * leveraging of existing file system interface functionality
2249 * to support the construction, deletion, and manipulation of
2252 * The special files "." and ".." retain their accustomed
2253 * semantics within the attribute hierarchy. The "." attribute
2254 * file refers to the current directory and the ".." attribute
2255 * file refers to the parent directory. The unnamed directory
2256 * at the head of each attribute tree is considered the "child"
2257 * of the file it is associated with and the ".." file refers
2258 * to the associated file. For any non-directory file with
2259 * attributes, the ".." entry in the unnamed directory refers
2260 * to a file that is not a directory.
2262 * Conceptually, the attribute model is fully general. Extended
2263 * attributes can be any type of file (doors, links, direc-
2264 * tories, and so forth) and can even have their own attributes
2265 * (fully recursive). As a result, the attributes associated
2266 * with a file could be an arbitrarily deep directory hierarchy
2267 * where each attribute could have an equally complex attribute
2268 * tree associated with it. Not all implementations are able
2269 * to, or want to, support the full model. Implementation are
2270 * therefore permitted to reject operations that are not sup-
2271 * ported. For example, the implementation for the UFS file
2272 * system allows only regular files as attributes (for example,
2273 * no sub-directories) and rejects attempts to place attributes
2276 * The following list details the operations that are rejected
2277 * in the current implementation:
2279 * link Any attempt to create links between
2280 * attribute and non-attribute space
2281 * is rejected to prevent security-
2282 * related or otherwise sensitive
2283 * attributes from being exposed, and
2284 * therefore manipulable, as regular
2287 * rename Any attempt to rename between
2288 * attribute and non-attribute space
2289 * is rejected to prevent an already
2290 * linked file from being renamed and
2291 * thereby circumventing the link res-
2294 * mkdir, symlink, mknod Any attempt to create a "non-
2295 * regular" file in attribute space is
2296 * rejected to reduce the functional-
2297 * ity, and therefore exposure and
2298 * risk, of the initial implementa-
2301 * The entire available name space has been allocated to "gen-
2302 * eral use" to bring the implementation in line with the NFSv4
2303 * draft standard [NFSv4]. That standard defines "named attri-
2304 * butes" (equivalent to Solaris Extended Attributes) with no
2305 * naming restrictions. All Sun applications making use of
2306 * opaque extended attributes will use the prefix "SUNW".
2309 #ifdef HAVE_SYS_ATTR_H
2310 #include <sys/attr.h>
2317 #ifdef HAVE_SYS_NVPAIR_H
2318 #include <sys/nvpair.h>
2321 #ifdef HAVE_SYS_ACL_H
2322 #include <sys/acl.h>
2325 #if !defined(HAVE_OPENAT) || \
2326 !defined(HAVE_UNLINKAT) || \
2327 !defined(HAVE_FCHOWNAT) || \
2328 !defined(HAVE_FUTIMESAT)
2329 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2333 * Define the supported XATTR streams for this OS
2335 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2336 static int os_default_xattr_streams[2] = {
2337 STREAM_XATTR_SOLARIS,
2338 STREAM_XATTR_SOLARIS_SYS
2341 static int os_default_xattr_streams[1] = {
2342 STREAM_XATTR_SOLARIS
2344 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2347 * This code creates a temporary cache with entries for each xattr which has
2348 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2350 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2352 xattr_link_cache_entry_t *ptr;
2354 foreach_alist(ptr, jcr->xattr_data->u.build->link_cache) {
2355 if (ptr && ptr->inum == inum) {
2362 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2364 xattr_link_cache_entry_t *ptr;
2366 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2367 memset(ptr, 0, sizeof(xattr_link_cache_entry_t));
2369 bstrncpy(ptr->target, target, sizeof(ptr->target));
2371 if (!jcr->xattr_data->u.build->link_cache) {
2372 jcr->xattr_data->u.build->link_cache = New(alist(10, not_owned_by_alist));
2374 jcr->xattr_data->u.build->link_cache->append(ptr);
2377 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2379 * This function returns true if a non default extended system attribute
2380 * list is associated with fd and returns false when an error has occured
2381 * or when only extended system attributes other than archive,
2382 * av_modified or crtime are set.
2384 * The function returns true for the following cases:
2386 * - any extended system attribute other than the default attributes
2387 * ('archive', 'av_modified' and 'crtime') is set
2388 * - nvlist has NULL name string
2389 * - nvpair has data type of 'nvlist'
2390 * - default data type.
2392 static bool solaris_has_non_transient_extensible_attributes(int fd)
2400 bool retval = false;
2402 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2407 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2408 name = nvpair_name(pair);
2411 fattr = name_to_attr(name);
2417 type = nvpair_type(pair);
2419 case DATA_TYPE_BOOLEAN_VALUE:
2420 if (nvpair_value_boolean_value(pair, &value) != 0) {
2423 if (value && fattr != F_ARCHIVE &&
2424 fattr != F_AV_MODIFIED) {
2429 case DATA_TYPE_UINT64_ARRAY:
2430 if (fattr != F_CRTIME) {
2435 case DATA_TYPE_NVLIST:
2443 if (response != NULL) {
2444 nvlist_free(response);
2448 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2450 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2452 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2453 * There is no need to store those acls as we already store the stat bits too.
2455 static bool acl_is_trivial(int count, aclent_t *entries)
2460 for (n = 0; n < count; n++) {
2462 if (!(ace->a_type == USER_OBJ ||
2463 ace->a_type == GROUP_OBJ ||
2464 ace->a_type == OTHER_OBJ ||
2465 ace->a_type == CLASS_OBJ))
2470 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2472 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2475 #ifdef HAVE_EXTENDED_ACL
2481 * See if this attribute has an ACL
2483 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2484 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2486 * See if there is a non trivial acl on the file.
2488 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2489 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2492 return bxattr_exit_ok;
2495 _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2496 attrname, jcr->last_fname, be.bstrerror());
2497 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2498 attrname, jcr->last_fname, be.bstrerror());
2499 return bxattr_exit_error;
2504 #if defined(ACL_SID_FMT)
2506 * New format flag added in newer Solaris versions.
2508 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2510 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2511 #endif /* ACL_SID_FMT */
2513 *acl_text = acl_totext(aclp, flags);
2521 return bxattr_exit_ok;
2522 #else /* HAVE_EXTENDED_ACL */
2524 aclent_t *acls = NULL;
2528 * See if this attribute has an ACL
2531 n = facl(fd, GETACLCNT, 0, NULL);
2533 n = acl(attrname, GETACLCNT, 0, NULL);
2536 if (n >= MIN_ACL_ENTRIES) {
2537 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2538 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2539 acl(attrname, GETACL, n, acls) != n) {
2543 return bxattr_exit_ok;
2546 _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2547 attrname, jcr->last_fname, be.bstrerror());
2548 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2549 attrname, jcr->last_fname, be.bstrerror());
2551 return bxattr_exit_error;
2556 * See if there is a non trivial acl on the file.
2558 if (!acl_is_trivial(n, acls)) {
2559 if ((*acl_text = acltotext(acls, n)) == NULL) {
2561 _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2562 attrname, jcr->last_fname, be.bstrerror());
2563 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2564 attrname, jcr->last_fname, be.bstrerror());
2566 return bxattr_exit_error;
2576 return bxattr_exit_ok;
2577 #endif /* HAVE_EXTENDED_ACL */
2579 #else /* HAVE_ACL */
2580 return bxattr_exit_ok;
2581 #endif /* HAVE_ACL */
2585 * Forward declaration for recursive function call.
2587 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2590 * Save an extended or extensible attribute.
2591 * This is stored as an opaque stream of bytes with the following encoding:
2593 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2595 * or for a hardlinked or symlinked attribute
2597 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2599 * xattr_name can be a subpath relative to the file the xattr is on.
2600 * stat_buffer is the string representation of the stat struct.
2601 * acl_string is an acl text when a non trivial acl is set on the xattr.
2602 * actual_xattr_data is the content of the xattr file.
2604 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2605 const char *attrname, bool toplevel_hidden_dir, int stream)
2610 xattr_link_cache_entry_t *xlce;
2611 char target_attrname[PATH_MAX];
2612 char link_source[PATH_MAX];
2613 char *acl_text = NULL;
2614 char attribs[MAXSTRING];
2615 char buffer[XATTR_BUFSIZ];
2616 bxattr_exit_code retval = bxattr_exit_error;
2619 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2622 * Get the stats of the extended or extensible attribute.
2624 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2627 retval = bxattr_exit_ok;
2631 _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2632 target_attrname, jcr->last_fname, be.bstrerror());
2633 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2634 target_attrname, jcr->last_fname, be.bstrerror());
2640 * Based on the filetype perform the correct action. We support most filetypes here, more
2641 * then the actual implementation on Solaris supports so some code may never get executed
2642 * due to limitations in the implementation.
2644 switch (st.st_mode & S_IFMT) {
2649 * Get any acl on the xattr.
2651 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2655 * The current implementation of xattr on Solaris doesn't support this,
2656 * but if it ever does we are prepared.
2657 * Encode the stat struct into an ASCII representation.
2659 encode_stat(attribs, &st, sizeof(st), 0, stream);
2660 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2661 target_attrname, 0, attribs, 0,
2662 (acl_text) ? acl_text : "", 0);
2666 * Get any acl on the xattr.
2668 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2672 * See if this is the toplevel_hidden_dir being saved.
2674 if (toplevel_hidden_dir) {
2676 * Save the data for later storage when we encounter a real xattr.
2677 * We store the data in the jcr->xattr_data->u.build->content buffer
2678 * and flush that just before sending out the first real xattr.
2679 * Encode the stat struct into an ASCII representation and jump
2680 * out of the function.
2682 encode_stat(attribs, &st, sizeof(st), 0, stream);
2683 cnt = bsnprintf(buffer, sizeof(buffer),
2685 target_attrname, 0, attribs, 0,
2686 (acl_text) ? acl_text : "", 0);
2687 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2688 jcr->xattr_data->u.build->content_length = cnt;
2692 * The current implementation of xattr on Solaris doesn't support this,
2693 * but if it ever does we are prepared.
2694 * Encode the stat struct into an ASCII representation.
2696 encode_stat(attribs, &st, sizeof(st), 0, stream);
2697 cnt = bsnprintf(buffer, sizeof(buffer),
2699 target_attrname, 0, attribs, 0,
2700 (acl_text) ? acl_text : "", 0);
2705 * If this is a hardlinked file check the inode cache for a hit.
2707 if (st.st_nlink > 1) {
2709 * See if the cache already knows this inode number.
2711 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2713 * Generate a xattr encoding with the reference to the target in there.
2715 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2716 cnt = bsnprintf(buffer, sizeof(buffer),
2718 target_attrname, 0, attribs, 0, xlce->target, 0);
2719 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2720 jcr->xattr_data->u.build->content_length = cnt;
2721 retval = send_xattr_stream(jcr, stream);
2724 * For a hard linked file we are ready now, no need to recursively
2725 * save the attributes.
2731 * Store this hard linked file in the cache.
2732 * Store the name relative to the top level xattr space.
2734 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2738 * Get any acl on the xattr.
2740 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2745 * Encode the stat struct into an ASCII representation.
2747 encode_stat(attribs, &st, sizeof(st), 0, stream);
2748 cnt = bsnprintf(buffer, sizeof(buffer),
2750 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2753 * Open the extended or extensible attribute file.
2755 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2758 retval = bxattr_exit_ok;
2762 _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2763 target_attrname, jcr->last_fname, be.bstrerror());
2764 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2765 target_attrname, jcr->last_fname, be.bstrerror());
2772 * The current implementation of xattr on Solaris doesn't support this, but if it
2773 * ever does we are prepared.
2774 * Encode the stat struct into an ASCII representation.
2776 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2779 retval = bxattr_exit_ok;
2783 _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2784 target_attrname, jcr->last_fname, be.bstrerror());
2785 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2786 target_attrname, jcr->last_fname, be.bstrerror());
2792 * Generate a xattr encoding with the reference to the target in there.
2794 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2795 cnt = bsnprintf(buffer, sizeof(buffer),
2797 target_attrname, 0, attribs, 0, link_source, 0);
2798 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2799 jcr->xattr_data->u.build->content_length = cnt;
2800 retval = send_xattr_stream(jcr, stream);
2802 if (retval == bxattr_exit_ok) {
2803 jcr->xattr_data->u.build->nr_saved++;
2807 * For a soft linked file we are ready now, no need to recursively save the attributes.
2815 * See if this is the first real xattr being saved.
2816 * If it is save the toplevel_hidden_dir attributes first.
2817 * This is easy as its stored already in the
2818 * jcr->xattr_data->u.build->content buffer.
2820 if (jcr->xattr_data->u.build->nr_saved == 0) {
2821 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2822 if (retval != bxattr_exit_ok) {
2825 jcr->xattr_data->u.build->nr_saved++;
2828 pm_memcpy(jcr->xattr_data->u.build->content, buffer, cnt);
2829 jcr->xattr_data->u.build->content_length = cnt;
2832 * Only dump the content of regular files.
2834 switch (st.st_mode & S_IFMT) {
2836 if (st.st_size > 0) {
2838 * Protect ourself against things getting out of hand.
2840 if (st.st_size >= MAX_XATTR_STREAM) {
2842 _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2843 jcr->last_fname, MAX_XATTR_STREAM);
2847 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2848 jcr->xattr_data->u.build->content =
2849 check_pool_memory_size(jcr->xattr_data->u.build->content,
2850 jcr->xattr_data->u.build->content_length + cnt);
2851 memcpy(jcr->xattr_data->u.build->content +
2852 jcr->xattr_data->u.build->content_length, buffer, cnt);
2853 jcr->xattr_data->u.build->content_length += cnt;
2858 _("Unable to read content of xattr %s on file \"%s\"\n"),
2859 target_attrname, jcr->last_fname);
2860 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2861 target_attrname, jcr->last_fname);
2872 retval = send_xattr_stream(jcr, stream);
2873 if (retval == bxattr_exit_ok) {
2874 jcr->xattr_data->u.build->nr_saved++;
2879 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2880 * available on this extended attribute.
2883 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2886 * The recursive call could change our working dir so change back to the wanted workdir.
2888 if (fchdir(fd) < 0) {
2891 retval = bxattr_exit_ok;
2895 _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2896 jcr->last_fname, be.bstrerror());
2897 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2898 jcr->last_fname, fd, be.bstrerror());
2905 if (acl_text != NULL) {
2914 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2917 int fd, filefd = -1, attrdirfd = -1;
2920 char current_xattr_namespace[PATH_MAX];
2921 bxattr_exit_code retval = bxattr_exit_error;
2925 * Determine what argument to use. Use attr_parent when set
2926 * (recursive call) or jcr->last_fname for first call. Also save
2927 * the current depth of the xattr_space we are in.
2931 if (xattr_namespace) {
2932 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2933 xattr_namespace, attr_parent);
2935 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2938 name = jcr->last_fname;
2939 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2943 * Open the file on which to save the xattrs read-only.
2945 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2948 retval = bxattr_exit_ok;
2952 _("Unable to open file \"%s\": ERR=%s\n"),
2953 jcr->last_fname, be.bstrerror());
2954 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2955 jcr->last_fname, be.bstrerror());
2961 * Open the xattr naming space.
2963 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2967 * Gentile way of the system saying this type of xattr layering is not supported.
2968 * Which is not problem we just forget about this this xattr.
2969 * But as this is not an error we return a positive return value.
2971 retval = bxattr_exit_ok;
2974 retval = bxattr_exit_ok;
2978 _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2979 name, jcr->last_fname, be.bstrerror());
2980 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2981 name, jcr->last_fname, be.bstrerror());
2987 * We need to change into the attribute directory to determine if each of the
2988 * attributes should be saved.
2990 if (fchdir(attrdirfd) < 0) {
2992 _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2993 jcr->last_fname, be.bstrerror());
2994 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2995 jcr->last_fname, attrdirfd, be.bstrerror());
3000 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
3001 * else because the readdir returns "." entry after the extensible attr entry.
3002 * And as we want this entry before anything else we better just save its data.
3005 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
3006 true, STREAM_XATTR_SOLARIS);
3008 if ((fd = dup(attrdirfd)) == -1 ||
3009 (dirp = fdopendir(fd)) == (DIR *)NULL) {
3011 _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
3012 jcr->last_fname, be.bstrerror());
3013 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
3014 jcr->last_fname, fd, be.bstrerror());
3020 * Walk the namespace.
3022 while ((dp = readdir(dirp)) != NULL) {
3024 * Skip only the toplevel . dir.
3026 if (!attr_parent && bstrcmp(dp->d_name, "."))
3030 * Skip all .. directories
3032 if (bstrcmp(dp->d_name, ".."))
3035 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
3036 current_xattr_namespace, dp->d_name, jcr->last_fname);
3038 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3040 * We are not interested in read-only extensible attributes.
3042 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
3043 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
3044 current_xattr_namespace, dp->d_name, jcr->last_fname);
3050 * We are only interested in read-write extensible attributes
3051 * when they contain non-transient values.
3053 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
3055 * Determine if there are non-transient system attributes at the toplevel.
3056 * We need to provide a fd to the open file.
3058 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
3059 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
3060 current_xattr_namespace, dp->d_name, jcr->last_fname);
3067 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3068 false, STREAM_XATTR_SOLARIS_SYS);
3071 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
3076 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
3077 false, STREAM_XATTR_SOLARIS);
3081 retval = bxattr_exit_ok;
3084 if (attrdirfd != -1)
3092 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr,
3094 const char *attrname,
3097 #ifdef HAVE_EXTENDED_ACL
3102 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
3104 _("Unable to convert acl from text on file \"%s\"\n"),
3106 return bxattr_exit_error;
3109 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
3110 acl_set(attrname, aclp) != 0) {
3112 _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3113 attrname, jcr->last_fname, be.bstrerror());
3114 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3115 attrname, jcr->last_fname, be.bstrerror());
3116 return bxattr_exit_error;
3122 return bxattr_exit_ok;
3124 #else /* HAVE_EXTENDED_ACL */
3126 aclent_t *acls = NULL;
3129 acls = aclfromtext(acl_text, &n);
3131 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
3132 acl(attrname, SETACL, n, acls) != 0) {
3134 _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
3135 attrname, jcr->last_fname, be.bstrerror());
3136 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
3137 attrname, jcr->last_fname, be.bstrerror());
3138 return bxattr_exit_error;
3145 return bxattr_exit_ok;
3147 #endif /* HAVE_EXTENDED_ACL */
3150 #endif /* HAVE_ACL */
3152 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr,
3155 uint32_t content_length)
3158 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
3159 int used_bytes, cnt;
3160 char *bp, *target_attrname, *attribs;
3161 char *linked_target = NULL;
3162 char *acl_text = NULL;
3166 struct timeval times[2];
3167 bxattr_exit_code retval = bxattr_exit_error;
3171 * Parse the xattr stream. First the part that is the same for all xattrs.
3176 * The name of the target xattr has a leading / we are not interested
3177 * in that so skip it when decoding the string. We always start a the /
3178 * of the xattr space anyway.
3180 target_attrname = content + 1;
3181 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
3182 (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3188 * Open the file on which to restore the xattrs read-only.
3190 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
3192 _("Unable to open file \"%s\": ERR=%s\n"),
3193 jcr->last_fname, be.bstrerror());
3194 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
3195 jcr->last_fname, be.bstrerror());
3200 * Open the xattr naming space and make it the current working dir.
3202 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3204 _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
3205 jcr->last_fname, be.bstrerror());
3206 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
3207 jcr->last_fname, be.bstrerror());
3211 if (fchdir(attrdirfd) < 0) {
3213 _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
3214 jcr->last_fname, be.bstrerror());
3215 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
3216 jcr->last_fname, attrdirfd, be.bstrerror());
3221 * Try to open the correct xattr subdir based on the target_attrname given.
3222 * e.g. check if its a subdir attrname. Each / in the string makes us go
3225 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
3228 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
3230 _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3231 target_attrname, jcr->last_fname, be.bstrerror());
3232 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3233 target_attrname, jcr->last_fname, be.bstrerror());
3241 * Open the xattr naming space.
3243 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
3245 _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
3246 target_attrname, jcr->last_fname, be.bstrerror());
3247 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
3248 target_attrname, jcr->last_fname, be.bstrerror());
3256 * Make the xattr space our current workingdir.
3258 if (fchdir(attrdirfd) < 0) {
3260 _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
3261 target_attrname, jcr->last_fname, be.bstrerror());
3262 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
3263 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
3267 target_attrname = ++bp;
3271 * Decode the attributes from the stream.
3273 decode_stat(attribs, &st, sizeof(st), &inum);
3276 * Decode the next field (acl_text).
3278 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
3279 (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
3285 * Based on the filetype perform the correct action. We support most filetypes here, more
3286 * then the actual implementation on Solaris supports so some code may never get executed
3287 * due to limitations in the implementation.
3289 switch (st.st_mode & S_IFMT) {
3292 * The current implementation of xattr on Solaris doesn't support this,
3293 * but if it ever does we are prepared.
3295 unlinkat(attrdirfd, target_attrname, 0);
3296 if (mkfifo(target_attrname, st.st_mode) < 0) {
3298 _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3299 target_attrname, jcr->last_fname, be.bstrerror());
3300 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
3301 target_attrname, jcr->last_fname, be.bstrerror());
3308 * The current implementation of xattr on Solaris doesn't support this,
3309 * but if it ever does we are prepared.
3311 unlinkat(attrdirfd, target_attrname, 0);
3312 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3314 _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3315 target_attrname, jcr->last_fname, be.bstrerror());
3316 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3317 target_attrname, jcr->last_fname, be.bstrerror());
3323 * If its not the hidden_dir create the entry.
3324 * The current implementation of xattr on Solaris doesn't support this,
3325 * but if it ever does we are prepared.
3327 if (!bstrcmp(target_attrname, ".")) {
3328 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3329 if (mkdir(target_attrname, st.st_mode) < 0) {
3330 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3331 target_attrname, jcr->last_fname, be.bstrerror());
3332 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3333 target_attrname, jcr->last_fname, be.bstrerror());
3340 * See if this is a hard linked file. e.g. inum != 0
3345 unlinkat(attrdirfd, target_attrname, 0);
3346 if (link(linked_target, target_attrname) < 0) {
3348 _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3349 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3350 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3351 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3356 * Successfully restored xattr.
3358 retval = bxattr_exit_ok;
3361 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3362 (used_bytes = (bp - content)) >= (int32_t)content_length) {
3366 if (used_bytes < (int32_t)(content_length - 1))
3370 * Restore the actual xattr.
3372 if (!is_extensible) {
3373 unlinkat(attrdirfd, target_attrname, 0);
3376 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3378 _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3379 target_attrname, jcr->last_fname, be.bstrerror());
3380 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3381 target_attrname, jcr->last_fname, be.bstrerror());
3387 * Restore the actual data.
3389 if (st.st_size > 0) {
3390 used_bytes = (data - content);
3391 cnt = content_length - used_bytes;
3394 * Do a sanity check, the st.st_size should be the same as the number of bytes
3395 * we have available as data of the stream.
3397 if (cnt != st.st_size) {
3399 _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3400 target_attrname, jcr->last_fname);
3401 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3402 target_attrname, jcr->last_fname);
3407 cnt = write(attrfd, data, cnt);
3410 _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3411 target_attrname, jcr->last_fname, be.bstrerror());
3412 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3413 target_attrname, jcr->last_fname, be.bstrerror());
3419 cnt = content_length - used_bytes;
3425 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3429 if (symlink(linked_target, target_attrname) < 0) {
3431 _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3432 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3433 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3434 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3439 * Successfully restored xattr.
3441 retval = bxattr_exit_ok;
3448 * Restore owner and acl for non extensible attributes.
3450 if (!is_extensible) {
3451 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3455 * Gentile way of the system saying this type of xattr layering is not supported.
3456 * But as this is not an error we return a positive return value.
3458 retval = bxattr_exit_ok;
3461 retval = bxattr_exit_ok;
3465 _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3466 target_attrname, jcr->last_fname, be.bstrerror());
3467 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3468 target_attrname, jcr->last_fname, be.bstrerror());
3475 if (acl_text && *acl_text)
3476 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3478 #endif /* HAVE_ACL */
3481 * For a non extensible attribute restore access and modification time on the xattr.
3483 if (!is_extensible) {
3484 times[0].tv_sec = st.st_atime;
3485 times[0].tv_usec = 0;
3486 times[1].tv_sec = st.st_mtime;
3487 times[1].tv_usec = 0;
3489 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3491 _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3492 target_attrname, jcr->last_fname, be.bstrerror());
3493 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3494 target_attrname, jcr->last_fname, be.bstrerror());
3500 * Successfully restored xattr.
3502 retval = bxattr_exit_ok;
3507 _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3509 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3516 if (attrdirfd != -1) {
3525 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3528 bxattr_exit_code retval = bxattr_exit_ok;
3531 * First see if extended attributes or extensible attributes are present.
3532 * If not just pretend things went ok.
3534 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3535 jcr->xattr_data->u.build->nr_saved = 0;
3538 * As we change the cwd in the save function save the current cwd
3539 * for restore after return from the solaris_save_xattrs function.
3541 getcwd(cwd, sizeof(cwd));
3542 retval = solaris_save_xattrs(jcr, NULL, NULL);
3544 if (jcr->xattr_data->u.build->link_cache) {
3545 delete jcr->xattr_data->u.build->link_cache;
3546 jcr->xattr_data->u.build->link_cache = NULL;
3552 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr,
3555 uint32_t content_length)
3558 bool is_extensible = false;
3559 bxattr_exit_code retval;
3562 * First make sure we can restore xattr on the filesystem.
3565 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3566 case STREAM_XATTR_SOLARIS_SYS:
3567 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3569 _("Failed to restore extensible attributes on file \"%s\"\n"),
3571 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3573 return bxattr_exit_error;
3576 is_extensible = true;
3579 case STREAM_XATTR_SOLARIS:
3580 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3582 _("Failed to restore extended attributes on file \"%s\"\n"),
3584 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3586 return bxattr_exit_error;
3590 return bxattr_exit_error;
3594 * As we change the cwd in the restore function save the current cwd
3595 * for restore after return from the solaris_restore_xattrs function.
3597 getcwd(cwd, sizeof(cwd));
3598 retval = solaris_restore_xattrs(jcr, is_extensible, content, content_length);
3605 * Function pointers to the build and parse function to use for these xattrs.
3607 static bxattr_exit_code (*os_build_xattr_streams)
3608 (JCR *jcr, FF_PKT *ff_pkt) =
3609 solaris_build_xattr_streams;
3610 static bxattr_exit_code (*os_parse_xattr_streams)
3611 (JCR *jcr, int stream, char *content, uint32_t content_length) =
3612 solaris_parse_xattr_streams;
3614 #endif /* defined(HAVE_SUN_OS) */
3617 * Entry points when compiled with support for XATTRs on a supported platform.
3619 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3622 * See if we are changing from one device to an other.
3623 * We save the current device we are scanning and compare
3624 * it with the current st_dev in the last stat performed on
3625 * the file we are currently storing.
3627 if (jcr->xattr_data->current_dev != ff_pkt->statp.st_dev) {
3629 * Reset the acl save flags.
3631 jcr->xattr_data->flags = 0;
3632 jcr->xattr_data->flags |= BXATTR_FLAG_SAVE_NATIVE;
3635 * Save that we started scanning a new filesystem.
3637 jcr->xattr_data->current_dev = ff_pkt->statp.st_dev;
3640 if ((jcr->xattr_data->flags & BXATTR_FLAG_SAVE_NATIVE) && os_parse_xattr_streams) {
3641 return os_build_xattr_streams(jcr, ff_pkt);
3643 return bxattr_exit_ok;
3647 bxattr_exit_code parse_xattr_streams(JCR *jcr,
3650 uint32_t content_length)
3658 * See if we are changing from one device to an other.
3659 * We save the current device we are restoring to and compare
3660 * it with the current st_dev in the last stat performed on
3661 * the file we are currently restoring.
3663 ret = lstat(jcr->last_fname, &st);
3668 return bxattr_exit_ok;
3671 _("Unable to stat file \"%s\": ERR=%s\n"),
3672 jcr->last_fname, be.bstrerror());
3673 Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n",
3674 jcr->last_fname, be.bstrerror());
3675 return bxattr_exit_error;
3681 if (jcr->xattr_data->current_dev != st.st_dev) {
3683 * Reset the acl save flags.
3685 jcr->xattr_data->flags = 0;
3686 jcr->xattr_data->flags |= BXATTR_FLAG_RESTORE_NATIVE;
3689 * Save that we started restoring to a new filesystem.
3691 jcr->xattr_data->current_dev = st.st_dev;
3695 * See if we are still restoring native xattr to this filesystem.
3697 if ((jcr->xattr_data->flags & BXATTR_FLAG_RESTORE_NATIVE) && os_parse_xattr_streams) {
3699 * See if we can parse this stream, and ifso give it a try.
3701 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3702 if (os_default_xattr_streams[cnt] == stream) {
3703 return os_parse_xattr_streams(jcr, stream, content, content_length);
3708 * Increment error count but don't log an error again for the same filesystem.
3710 jcr->xattr_data->u.parse->nr_errors++;
3711 return bxattr_exit_ok;
3715 * Issue a warning and discard the message. But pretend the restore was ok.
3717 Jmsg2(jcr, M_WARNING, 0,
3718 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3719 jcr->last_fname, stream);
3720 return bxattr_exit_error;