2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2010 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
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, int stream)
68 return bxattr_exit_fatal;
72 * Send a XATTR stream to the SD.
74 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
76 BSOCK *sd = jcr->store_bsock;
78 #ifdef FD_NO_SEND_TEST
79 return bxattr_exit_ok;
85 if (jcr->xattr_data->content_length <= 0) {
86 return bxattr_exit_ok;
92 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
93 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
95 return bxattr_exit_fatal;
99 * Send the buffer to the storage deamon
101 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
103 sd->msg = jcr->xattr_data->content;
104 sd->msglen = jcr->xattr_data->content_length;
108 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
110 return bxattr_exit_fatal;
113 jcr->JobBytes += sd->msglen;
115 if (!sd->signal(BNET_EOD)) {
116 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
118 return bxattr_exit_fatal;
120 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
121 return bxattr_exit_ok;
125 * First some generic functions for OSes that use the same xattr encoding scheme.
126 * Currently for all OSes except for Solaris.
128 #if !defined(HAVE_SUN_OS)
129 static void xattr_drop_internal_table(alist *xattr_value_list)
131 xattr_t *current_xattr;
134 * Walk the list of xattrs and free allocated memory on traversing.
136 foreach_alist(current_xattr, xattr_value_list) {
138 * See if we can shortcut.
140 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
143 free(current_xattr->name);
145 if (current_xattr->value_length > 0)
146 free(current_xattr->value);
151 delete xattr_value_list;
155 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
156 * which encodes one or more xattr_t structures.
158 * The Serialized stream consists of the following elements:
159 * magic - A magic string which makes it easy to detect any binary incompatabilites
160 * name_length - The length of the following xattr name
161 * name - The name of the extended attribute
162 * value_length - The length of the following xattr data
163 * value - The actual content of the extended attribute
165 * This is repeated 1 or more times.
168 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, alist *xattr_value_list)
170 xattr_t *current_xattr;
174 * Make sure the serialized stream fits in the poolmem buffer.
175 * We allocate some more to be sure the stream is gonna fit.
177 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
178 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
181 * Walk the list of xattrs and serialize the data.
183 foreach_alist(current_xattr, xattr_value_list) {
185 * See if we can shortcut.
187 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
190 ser_uint32(current_xattr->magic);
191 ser_uint32(current_xattr->name_length);
192 ser_bytes(current_xattr->name, current_xattr->name_length);
194 ser_uint32(current_xattr->value_length);
195 if (current_xattr->value_length > 0 && current_xattr->value) {
196 ser_bytes(current_xattr->value, current_xattr->value_length);
198 Dmsg3(100, "Backup xattr named %s, value %*s\n",
199 current_xattr->name, current_xattr->value, current_xattr->value);
201 Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
205 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
206 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
208 return jcr->xattr_data->content_length;
211 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
214 xattr_t *current_xattr;
215 bxattr_exit_code retval = bxattr_exit_ok;
218 * Parse the stream and call restore_xattr_on_file for each extended attribute.
220 * Start unserializing the data. We keep on looping while we have not
221 * unserialized all bytes in the stream.
223 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
224 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
226 * First make sure the magic is present. This way we can easily catch corruption.
227 * Any missing MAGIC is fatal we do NOT try to continue.
230 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
231 unser_uint32(current_xattr->magic);
232 if (current_xattr->magic != XATTR_MAGIC) {
233 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
235 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
238 return bxattr_exit_error;
242 * Decode the valuepair. First decode the length of the name.
244 unser_uint32(current_xattr->name_length);
245 if (current_xattr->name_length == 0) {
246 Mmsg1(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
248 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
251 return bxattr_exit_error;
255 * Allocate room for the name and decode its content.
257 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
258 unser_bytes(current_xattr->name, current_xattr->name_length);
261 * The xattr_name needs to be null terminated.
263 current_xattr->name[current_xattr->name_length] = '\0';
266 * Decode the value length.
268 unser_uint32(current_xattr->value_length);
270 if (current_xattr->value_length > 0) {
272 * Allocate room for the value and decode its content.
274 current_xattr->value = (char *)malloc(current_xattr->value_length);
275 unser_bytes(current_xattr->value, current_xattr->value_length);
277 Dmsg3(100, "Restoring xattr named %s, value %*s\n",
278 current_xattr->name, current_xattr->value, current_xattr->value);
280 current_xattr->value = NULL;
281 Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
284 xattr_value_list->append(current_xattr);
287 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
293 * This is a supported OS, See what kind of interface we should use.
295 #if defined(HAVE_AIX_OS)
297 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
298 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
299 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
300 #error "Missing full support for the Extended Attributes (EA) functions."
306 #error "Missing sys/ea.h header file"
310 * Define the supported XATTR streams for this OS
312 static int os_default_xattr_streams[1] = { STREAM_XATTR_AIX };
315 * Fallback to the non l-functions when those are not available.
317 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
320 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
323 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
324 #define llistea listea
327 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
330 char *xattr_list, *bp;
331 int cnt, xattr_count = 0;
332 uint32_t name_length;
333 int32_t xattr_list_len,
335 uint32_t expected_serialize_len = 0;
336 xattr_t *current_xattr = NULL;
337 alist *xattr_value_list = NULL;
338 bxattr_exit_code retval = bxattr_exit_error;
342 * First get the length of the available list with extended attributes.
344 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
345 switch (xattr_list_len) {
351 return bxattr_exit_ok;
353 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
354 jcr->last_fname, be.bstrerror());
355 Dmsg2(100, "llistea error file=%s ERR=%s\n",
356 jcr->last_fname, be.bstrerror());
357 return bxattr_exit_error;
361 return bxattr_exit_ok;
367 * Allocate room for the extented attribute list.
369 xattr_list = (char *)malloc(xattr_list_len + 1);
370 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
373 * Get the actual list of extended attributes names for a file.
375 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
376 switch (xattr_list_len) {
382 retval = bxattr_exit_ok;
385 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
386 jcr->last_fname, be.bstrerror());
387 Dmsg2(100, "llistea error file=%s ERR=%s\n",
388 jcr->last_fname, be.bstrerror());
395 xattr_list[xattr_list_len] = '\0';
398 * Walk the list of extended attributes names and retrieve the data.
399 * We already count the bytes needed for serializing the stream later on.
402 while ((bp - xattr_list) + 1 < xattr_list_len) {
406 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
412 name_length = strlen(bp);
413 if (skip_xattr || name_length == 0) {
414 Dmsg1(100, "Skipping xattr named %s\n", bp);
415 bp = strchr(bp, '\0') + 1;
420 * Each xattr valuepair starts with a magic so we can parse it easier.
422 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
423 current_xattr->magic = XATTR_MAGIC;
424 expected_serialize_len += sizeof(current_xattr->magic);
427 * Allocate space for storing the name.
429 current_xattr->name_length = name_length;
430 current_xattr->name = (char *)malloc(current_xattr->name_length);
431 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
433 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
436 * First see how long the value is for the extended attribute.
438 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
439 switch (xattr_value_len) {
445 retval = bxattr_exit_ok;
448 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
449 jcr->last_fname, be.bstrerror());
450 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
451 jcr->last_fname, be.bstrerror());
456 current_xattr->value = NULL;
457 current_xattr->value_length = 0;
458 expected_serialize_len += sizeof(current_xattr->value_length);
462 * Allocate space for storing the value.
464 current_xattr->value = (char *)malloc(xattr_value_len);
465 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
467 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
468 if (xattr_value_len < 0) {
473 retval = bxattr_exit_ok;
476 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
477 jcr->last_fname, be.bstrerror());
478 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
479 jcr->last_fname, be.bstrerror());
484 * Store the actual length of the value.
486 current_xattr->value_length = xattr_value_len;
487 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
490 * Protect ourself against things getting out of hand.
492 if (expected_serialize_len >= MAX_XATTR_STREAM) {
493 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
494 jcr->last_fname, MAX_XATTR_STREAM);
499 if (xattr_value_list == NULL) {
500 xattr_value_list = New(alist(10, not_owned_by_alist));
503 xattr_value_list->append(current_xattr);
504 current_xattr = NULL;
506 bp = strchr(bp, '\0') + 1;
511 xattr_list = (char *)NULL;
514 * If we found any xattr send them to the SD.
516 if (xattr_count > 0) {
518 * Serialize the datastream.
520 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
521 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
523 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
529 * Send the datastream to the SD.
531 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
533 retval = bxattr_exit_ok;
537 if (current_xattr != NULL) {
538 if (current_xattr->value != NULL) {
539 free(current_xattr->value);
541 if (current_xattr->name != NULL) {
542 free(current_xattr->name);
546 if (xattr_list != NULL) {
549 if (xattr_value_list != NULL) {
550 xattr_drop_internal_table(xattr_value_list);
555 static bxattr_exit_code aix_xattr_parse_streams(JCR *jcr, int stream)
557 xattr_t *current_xattr;
558 alist *xattr_value_list;
561 xattr_value_list = New(alist(10, not_owned_by_alist));
563 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
564 xattr_drop_internal_table(xattr_value_list);
565 return bxattr_exit_error;
568 foreach_alist(current_xattr, xattr_value_list) {
569 if (lsetea(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
576 Mmsg2(jcr->errmsg, _("lsetea error on file \"%s\": ERR=%s\n"),
577 jcr->last_fname, be.bstrerror());
578 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
579 jcr->last_fname, be.bstrerror());
585 xattr_drop_internal_table(xattr_value_list);
586 return bxattr_exit_ok;
589 xattr_drop_internal_table(xattr_value_list);
590 return bxattr_exit_error;
594 * Function pointers to the build and parse function to use for these xattrs.
596 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_xattr_build_streams;
597 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = aix_xattr_parse_streams;
599 #elif defined(HAVE_IRIX_OS)
602 * Define the supported XATTR streams for this OS
604 static int os_default_xattr_streams[1] = { STREAM_XATTR_IRIX };
605 static const char *xattr_acl_skiplist[1] = { NULL };
606 static const char *xattr_skiplist[1] = { NULL };
608 struct xattr_naming_space {
613 static xattr_naming_space xattr_naming_spaces[] = {
614 { "user.", ATTR_DONTFOLLOW },
615 { "root.", ATTR_ROOT | ATTR_DONTFOLLOW },
619 static bxattr_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
621 int cnt, xattr_count = 0;
622 attrlist_cursor_t cursor;
623 attrlist_t *attrlist;
624 attrlist_ent_t *attrlist_ent;
625 xattr_t *current_xattr = NULL;
626 alist *xattr_value_list = NULL;
627 uint32_t expected_serialize_len = 0;
628 bxattr_exit_code retval = bxattr_exit_error;
629 POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
632 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
633 memset(cursor, 0, sizeof(attrlist_cursor_t));
635 if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
636 xattr_naming_spaces[cnt].flags, &cursor) != 0) {
639 retval = bxattr_exit_ok;
642 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
643 jcr->last_fname, be.bstrerror());
644 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
645 jcr->last_fname, be.bstrerror());
650 attrlist = (attrlist_t *)xattrbuf;
653 * Walk the available attributes.
655 for (cnt = 0; cnt < attrlist->al_count; cnt++) {
656 attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
659 * Each xattr valuepair starts with a magic so we can parse it easier.
661 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
662 current_xattr->magic = XATTR_MAGIC;
663 expected_serialize_len += sizeof(current_xattr->magic);
666 * Allocate space for storing the name.
667 * We store the name as <naming_space_name><xattr_name>
669 current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) + strlen(attrlist_ent->a_name) + 1;
670 current_xattr->name = (char *)malloc(current_xattr->name_length);
671 bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
672 xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
674 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
676 current_xattr->value_length = attrlist_ent->a_valuelen;
677 current_xattr->value = (char *)malloc(current_xattr->value_length);
680 * Retrieve the actual value of the xattr.
682 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
683 current_xattr->value_length, xattr_naming_spaces[cnt].flags) != 0) {
687 retval = bxattr_exit_ok;
691 * The buffer for the xattr isn't big enough. the value of
692 * current_xattr->value_length is updated with the actual size
693 * of the xattr. So we free the old buffer and create a new one
696 free(current_xattr->value);
697 current_xattr->value = (char *)malloc(current_xattr->value_length);
698 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
699 current_xattr->value_length, xattr_naming_spaces[cnt].flags) != 0) {
703 retval = bxattr_exit_ok;
706 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
707 jcr->last_fname, be.bstrerror());
708 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
709 jcr->last_fname, be.bstrerror());
715 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
716 jcr->last_fname, be.bstrerror());
717 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
718 jcr->last_fname, be.bstrerror());
723 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
726 * Protect ourself against things getting out of hand.
728 if (expected_serialize_len >= MAX_XATTR_STREAM) {
729 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
730 jcr->last_fname, MAX_XATTR_STREAM);
734 if (xattr_value_list == NULL) {
735 xattr_value_list = New(alist(10, not_owned_by_alist));
738 xattr_value_list->append(current_xattr);
739 current_xattr = NULL;
744 * See if there are more attributes available for a next run of attr_list.
746 if (attrlist->al_more == 0) {
753 * If we found any xattr send them to the SD.
755 if (xattr_count > 0) {
757 * Serialize the datastream.
759 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
760 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
762 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
768 * Send the datastream to the SD.
770 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
772 retval = bxattr_exit_ok;
776 if (current_xattr != NULL) {
777 if (current_xattr->value != NULL) {
778 free(current_xattr->value);
780 if (current_xattr->name != NULL) {
781 free(current_xattr->name);
785 free_pool_memory(xattrbuf);
787 if (xattr_value_list != NULL) {
788 xattr_drop_internal_table(xattr_value_list);
793 static bxattr_exit_code irix_xattr_parse_streams(JCR *jcr, int stream)
796 int cnt, cmp_size, name_space_index;
797 xattr_t *current_xattr;
798 alist *xattr_value_list;
801 xattr_value_list = New(alist(10, not_owned_by_alist));
803 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
804 xattr_drop_internal_table(xattr_value_list);
805 return bxattr_exit_error;
808 foreach_alist(current_xattr, xattr_value_list) {
810 * See to what namingspace this xattr belongs to.
812 name_space_index = 0;
813 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
814 cmp_size = strlen(xattr_naming_spaces[cnt].name);
815 if (!strncasecmp(current_xattr->name,
816 xattr_naming_spaces[cnt].name,
818 name_space_index = cnt;
824 * If we got a xattr that doesn't belong to ant valid namespace complain.
826 if (name_space_index == 0) {
827 Mmsg2(jcr->errmsg, _("Received illegal xattr named %s on file \"%s\"\n"),
828 current_xattr->name, jcr->last_fname);
829 Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
830 current_xattr->name, jcr->last_fname);
835 * Restore the xattr first try to create the attribute from scratch.
837 flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
838 bp = strchr(current_xattr->name, '.');
839 if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
840 current_xattr->value_len, flags) != 0) {
843 retval = bxattr_exit_ok;
847 * The xattr already exists we need to replace it.
849 flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
850 if (attr_set(jcr->last_fname, bp, current_xattr->value,
851 current_xattr->value_len, flags) != 0) {
854 retval = bxattr_exit_ok;
857 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
858 jcr->last_fname, be.bstrerror());
859 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
860 jcr->last_fname, be.bstrerror());
866 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
867 jcr->last_fname, be.bstrerror());
868 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
869 jcr->last_fname, be.bstrerror());
875 xattr_drop_internal_table(xattr_value_list);
876 return bxattr_exit_ok;
879 xattr_drop_internal_table(xattr_value_list);
880 return bxattr_exit_error;
884 * Function pointers to the build and parse function to use for these xattrs.
886 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = irix_xattr_build_streams;
887 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = irix_xattr_parse_streams;
889 #elif defined(HAVE_DARWIN_OS) || \
890 defined(HAVE_LINUX_OS)
892 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
893 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
894 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
895 #error "Missing full support for the XATTR functions."
898 #ifdef HAVE_SYS_XATTR_H
899 #include <sys/xattr.h>
901 #error "Missing sys/xattr.h header file"
905 * Define the supported XATTR streams for this OS
907 #if defined(HAVE_DARWIN_OS)
908 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
909 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
910 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
911 #elif defined(HAVE_LINUX_OS)
912 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
913 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
914 static const char *xattr_skiplist[1] = { NULL };
918 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
919 * listxattr, getxattr and setxattr with an extra options argument
920 * which mimics the l variants of the functions when we specify
921 * XATTR_NOFOLLOW as the options value.
923 #if defined(HAVE_DARWIN_OS)
924 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
925 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
926 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
929 * Fallback to the non l-functions when those are not available.
931 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
932 #define lgetxattr getxattr
934 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
935 #define lsetxattr setxattr
937 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
938 #define llistxattr listxattr
942 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
945 char *xattr_list, *bp;
946 int cnt, xattr_count = 0;
947 int32_t xattr_list_len,
949 uint32_t expected_serialize_len = 0;
950 xattr_t *current_xattr = NULL;
951 alist *xattr_value_list = NULL;
952 bxattr_exit_code retval = bxattr_exit_error;
956 * First get the length of the available list with extended attributes.
958 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
959 switch (xattr_list_len) {
964 return bxattr_exit_ok;
966 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
967 jcr->last_fname, be.bstrerror());
968 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
969 jcr->last_fname, be.bstrerror());
970 return bxattr_exit_error;
974 return bxattr_exit_ok;
980 * Allocate room for the extented attribute list.
982 xattr_list = (char *)malloc(xattr_list_len + 1);
983 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
986 * Get the actual list of extended attributes names for a file.
988 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
989 switch (xattr_list_len) {
994 retval = bxattr_exit_ok;
997 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
998 jcr->last_fname, be.bstrerror());
999 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1000 jcr->last_fname, be.bstrerror());
1007 xattr_list[xattr_list_len] = '\0';
1010 * Walk the list of extended attributes names and retrieve the data.
1011 * We already count the bytes needed for serializing the stream later on.
1014 while ((bp - xattr_list) + 1 < xattr_list_len) {
1019 * On some OSes you also get the acls in the extented attribute list.
1020 * So we check if we are already backing up acls and if we do we
1021 * don't store the extended attribute with the same info.
1023 if (ff_pkt->flags & FO_ACL) {
1024 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1025 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1033 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1036 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1037 if (bstrcmp(bp, xattr_skiplist[cnt])) {
1044 name_len = strlen(bp);
1045 if (skip_xattr || name_len == 0) {
1046 Dmsg1(100, "Skipping xattr named %s\n", bp);
1047 bp = strchr(bp, '\0') + 1;
1052 * Each xattr valuepair starts with a magic so we can parse it easier.
1054 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1055 current_xattr->magic = XATTR_MAGIC;
1056 expected_serialize_len += sizeof(current_xattr->magic);
1059 * Allocate space for storing the name.
1061 current_xattr->name_length = name_len;
1062 current_xattr->name = (char *)malloc(current_xattr->name_length);
1063 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
1065 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1068 * First see how long the value is for the extended attribute.
1070 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1071 switch (xattr_value_len) {
1076 retval = bxattr_exit_ok;
1079 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1080 jcr->last_fname, be.bstrerror());
1081 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1082 jcr->last_fname, be.bstrerror());
1087 current_xattr->value = NULL;
1088 current_xattr->value_length = 0;
1089 expected_serialize_len += sizeof(current_xattr->value_length);
1093 * Allocate space for storing the value.
1095 current_xattr->value = (char *)malloc(xattr_value_len);
1096 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1098 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1099 if (xattr_value_len < 0) {
1103 retval = bxattr_exit_ok;
1106 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1107 jcr->last_fname, be.bstrerror());
1108 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1109 jcr->last_fname, be.bstrerror());
1114 * Store the actual length of the value.
1116 current_xattr->value_length = xattr_value_len;
1117 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1120 * Protect ourself against things getting out of hand.
1122 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1123 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1124 jcr->last_fname, MAX_XATTR_STREAM);
1129 if (xattr_value_list == NULL) {
1130 xattr_value_list = New(alist(10, not_owned_by_alist));
1133 xattr_value_list->append(current_xattr);
1134 current_xattr = NULL;
1136 bp = strchr(bp, '\0') + 1;
1141 xattr_list = (char *)NULL;
1144 * If we found any xattr send them to the SD.
1146 if (xattr_count > 0) {
1148 * Serialize the datastream.
1150 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1151 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1153 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1159 * Send the datastream to the SD.
1161 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1163 retval = bxattr_exit_ok;
1167 if (current_xattr != NULL) {
1168 if (current_xattr->value != NULL) {
1169 free(current_xattr->value);
1171 if (current_xattr->name != NULL) {
1172 free(current_xattr->name);
1174 free(current_xattr);
1176 if (xattr_list != NULL) {
1179 if (xattr_value_list != NULL) {
1180 xattr_drop_internal_table(xattr_value_list);
1185 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
1187 xattr_t *current_xattr;
1188 alist *xattr_value_list;
1191 xattr_value_list = New(alist(10, not_owned_by_alist));
1193 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1194 xattr_drop_internal_table(xattr_value_list);
1195 return bxattr_exit_error;
1198 foreach_alist(current_xattr, xattr_value_list) {
1199 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1205 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
1206 jcr->last_fname, be.bstrerror());
1207 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1208 jcr->last_fname, be.bstrerror());
1214 xattr_drop_internal_table(xattr_value_list);
1215 return bxattr_exit_ok;
1218 xattr_drop_internal_table(xattr_value_list);
1219 return bxattr_exit_error;
1223 * Function pointers to the build and parse function to use for these xattrs.
1225 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
1226 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
1228 #elif defined(HAVE_FREEBSD_OS) || \
1229 defined(HAVE_NETBSD_OS) || \
1230 defined(HAVE_OPENBSD_OS)
1232 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1233 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1234 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1235 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1236 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1237 #error "Missing full support for the extattr functions."
1240 #ifdef HAVE_SYS_EXTATTR_H
1241 #include <sys/extattr.h>
1243 #error "Missing sys/extattr.h header file"
1246 #ifdef HAVE_LIBUTIL_H
1247 #include <libutil.h>
1250 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1251 #define extattr_get_link extattr_get_file
1253 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1254 #define extattr_set_link extattr_set_file
1256 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1257 #define extattr_list_link extattr_list_file
1260 #if defined(HAVE_FREEBSD_OS)
1261 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
1262 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1263 static const char *xattr_acl_skiplist[2] = { "system.posix1e.acl_access", NULL };
1264 static const char *xattr_skiplist[1] = { NULL };
1265 #elif defined(HAVE_NETBSD_OS)
1266 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
1267 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1268 static const char *xattr_acl_skiplist[1] = { NULL };
1269 static const char *xattr_skiplist[1] = { NULL };
1270 #elif defined(HAVE_OPENBSD_OS)
1271 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
1272 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1273 static const char *xattr_acl_skiplist[1] = { NULL };
1274 static const char *xattr_skiplist[1] = { NULL };
1277 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1281 int cnt, index, xattr_count = 0;
1282 int32_t xattr_list_len,
1284 uint32_t expected_serialize_len = 0;
1285 unsigned int namespace_index;
1287 char *current_attrnamespace = NULL;
1288 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1289 xattr_t *current_xattr = NULL;
1290 alist *xattr_value_list = NULL;
1291 bxattr_exit_code retval = bxattr_exit_error;
1295 * Loop over all available xattr namespaces.
1297 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
1298 attrnamespace = os_default_xattr_namespaces[namespace_index];
1301 * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
1302 * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
1304 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1305 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
1306 attrnamespace, jcr->last_fname);
1307 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1308 attrnamespace, jcr->last_fname);
1313 * First get the length of the available list with extended attributes.
1314 * If we get EPERM on system namespace, don't return error.
1315 * This is expected for normal users trying to archive the system
1316 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1317 * they've decided to return EOPNOTSUPP instead.
1319 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1320 switch (xattr_list_len) {
1324 retval = bxattr_exit_ok;
1326 #if defined(EOPNOTSUPP)
1330 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1331 actuallyfree(current_attrnamespace);
1332 current_attrnamespace = NULL;
1339 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1340 jcr->last_fname, be.bstrerror());
1341 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1342 jcr->last_fname, be.bstrerror());
1353 * Allocate room for the extented attribute list.
1355 xattr_list = (char *)malloc(xattr_list_len + 1);
1356 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
1359 * Get the actual list of extended attributes names for a file.
1361 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
1362 switch (xattr_list_len) {
1366 retval = bxattr_exit_ok;
1369 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1370 jcr->last_fname, be.bstrerror());
1371 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1372 jcr->last_fname, be.bstrerror());
1379 xattr_list[xattr_list_len] = '\0';
1382 * Walk the list of extended attributes names and retrieve the data.
1383 * We already count the bytes needed for serializing the stream later on.
1385 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1389 * Print the current name into the buffer as its not null terminated we need to
1390 * use the length encoded in the string for copying only the needed bytes.
1392 cnt = xattr_list[index];
1393 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1394 cnt = ((int)sizeof(current_attrname) - 1);
1396 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1397 current_attrname[cnt] = '\0';
1400 * First make a xattr tuple of the current namespace and the name of the xattr.
1401 * e.g. something like user.<attrname> or system.<attrname>
1403 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
1406 * On some OSes you also get the acls in the extented attribute list.
1407 * So we check if we are already backing up acls and if we do we
1408 * don't store the extended attribute with the same info.
1410 if (ff_pkt->flags & FO_ACL) {
1411 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1412 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1420 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1423 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1424 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1432 Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1437 * Each xattr valuepair starts with a magic so we can parse it easier.
1439 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1440 current_xattr->magic = XATTR_MAGIC;
1441 expected_serialize_len += sizeof(current_xattr->magic);
1444 * Allocate space for storing the name.
1446 current_xattr->name_length = strlen(current_attrtuple);
1447 current_xattr->name = (char *)malloc(current_xattr->name_length);
1448 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
1450 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1453 * First see how long the value is for the extended attribute.
1455 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
1456 switch (xattr_value_len) {
1460 retval = bxattr_exit_ok;
1463 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1464 jcr->last_fname, be.bstrerror());
1465 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1466 jcr->last_fname, be.bstrerror());
1471 current_xattr->value = NULL;
1472 current_xattr->value_length = 0;
1473 expected_serialize_len += sizeof(current_xattr->value_length);
1477 * Allocate space for storing the value.
1479 current_xattr->value = (char *)malloc(xattr_value_len);
1480 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1482 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
1483 if (xattr_value_len < 0) {
1486 retval = bxattr_exit_ok;
1489 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1490 jcr->last_fname, be.bstrerror());
1491 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1492 jcr->last_fname, be.bstrerror());
1498 * Store the actual length of the value.
1500 current_xattr->value_length = xattr_value_len;
1501 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1504 * Protect ourself against things getting out of hand.
1506 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1507 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1508 jcr->last_fname, MAX_XATTR_STREAM);
1514 if (xattr_value_list == NULL) {
1515 xattr_value_list = New(alist(10, not_owned_by_alist));
1518 xattr_value_list->append(current_xattr);
1519 current_xattr = NULL;
1525 * Drop the local copy of the current_attrnamespace.
1527 actuallyfree(current_attrnamespace);
1528 current_attrnamespace = NULL;
1531 * We are done with this xattr list.
1534 xattr_list = (char *)NULL;
1538 * If we found any xattr send them to the SD.
1540 if (xattr_count > 0) {
1542 * Serialize the datastream.
1544 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1545 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1547 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1553 * Send the datastream to the SD.
1555 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1557 retval = bxattr_exit_ok;
1561 if (current_attrnamespace != NULL) {
1562 actuallyfree(current_attrnamespace);
1564 if (current_xattr != NULL) {
1565 if (current_xattr->value != NULL) {
1566 free(current_xattr->value);
1568 if (current_xattr->name != NULL) {
1569 free(current_xattr->name);
1571 free(current_xattr);
1573 if (xattr_list != NULL) {
1576 if (xattr_value_list != NULL) {
1577 xattr_drop_internal_table(xattr_value_list);
1582 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
1584 xattr_t *current_xattr;
1585 alist *xattr_value_list;
1586 int current_attrnamespace, cnt;
1587 char *attrnamespace, *attrname;
1590 xattr_value_list = New(alist(10, not_owned_by_alist));
1592 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1593 xattr_drop_internal_table(xattr_value_list);
1594 return bxattr_exit_error;
1597 foreach_alist(current_xattr, xattr_value_list) {
1599 * Try splitting the xattr_name into a namespace and name part.
1600 * The splitting character is a .
1602 attrnamespace = current_xattr->name;
1603 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1604 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1605 current_xattr->name, jcr->last_fname);
1606 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1607 current_xattr->name, jcr->last_fname);
1613 * Make sure the attrnamespace makes sense.
1615 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1616 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1617 attrnamespace, jcr->last_fname);
1618 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1619 attrnamespace, jcr->last_fname);
1624 * Try restoring the extended attribute.
1626 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1627 attrname, current_xattr->value, current_xattr->value_length);
1628 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1634 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1635 jcr->last_fname, be.bstrerror());
1636 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1637 jcr->last_fname, be.bstrerror());
1644 xattr_drop_internal_table(xattr_value_list);
1645 return bxattr_exit_ok;
1648 xattr_drop_internal_table(xattr_value_list);
1649 return bxattr_exit_error;
1653 * Function pointers to the build and parse function to use for these xattrs.
1655 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1656 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1658 #elif defined(HAVE_OSF1_OS)
1660 #if !defined(HAVE_GETPROPLIST) || \
1661 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1662 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1663 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1664 !defined(HAVE_SETPROPLIST)
1665 #error "Missing full support for the Extended Attributes functions."
1668 #ifdef HAVE_SYS_PROPLIST_H
1669 #include <sys/proplist.h>
1671 #error "Missing sys/proplist.h header file"
1675 * Define the supported XATTR streams for this OS
1677 static int os_default_xattr_streams[1] = { STREAM_XATTR_TRU64 };
1678 static const char *xattr_acl_skiplist[1] = { NULL };
1679 static const char *xattr_skiplist[1] = { NULL };
1681 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1687 int xattr_count = 0;
1690 int32_t xattr_list_len,
1693 uint32_t expected_serialize_len = 0;
1694 xattr_t *current_xattr = NULL;
1695 alist *xattr_value_list = NULL;
1696 struct proplistname_args prop_args;
1697 bxattr_exit_code retval = bxattr_exit_error;
1698 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1701 xattrbuf_size = sizeof_pool_memory(xattrbuf);
1702 xattrbuf_min_size = 0;
1703 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1704 xattrbuf, &xattrbuf_min_size);
1707 * See what xattr are available.
1709 switch (xattr_list_len) {
1713 retval = bacl_exit_ok;
1716 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1717 jcr->last_fname, be.bstrerror());
1718 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1719 jcr->last_fname, be.bstrerror());
1724 if (xattrbuf_min_size) {
1726 * The buffer isn't big enough to hold the xattr data, we now have
1727 * a minimum buffersize so we resize the buffer and try again.
1729 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1730 xattrbuf_size = xattrbuf_min_size + 1;
1731 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1732 xattrbuf, &xattrbuf_min_size);
1733 switch (xattr_list_len) {
1737 retval = bacl_exit_ok;
1740 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1741 jcr->last_fname, be.bstrerror());
1742 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1743 jcr->last_fname, be.bstrerror());
1749 * This should never happen as we sized the buffer according to the minimumsize
1750 * returned by a previous getproplist call. If it does happen things are fishy and
1751 * we are better of forgetting this xattr as it seems its list is changing at this
1752 * exact moment so we can never make a good backup copy of it.
1754 retval = bacl_exit_ok;
1763 retval = bacl_exit_ok;
1772 * Walk the list of extended attributes names and retrieve the data.
1773 * We already count the bytes needed for serializing the stream later on.
1776 while (xattrbuf_size > 0) {
1778 * Call getproplist_entry to initialize name and value
1779 * pointers to entries position within buffer.
1781 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
1784 * On some OSes you also get the acls in the extented attribute list.
1785 * So we check if we are already backing up acls and if we do we
1786 * don't store the extended attribute with the same info.
1788 if (ff_pkt->flags & FO_ACL) {
1789 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1790 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
1798 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1801 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1802 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
1810 Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
1815 * Each xattr valuepair starts with a magic so we can parse it easier.
1817 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1818 current_xattr->magic = XATTR_MAGIC;
1819 expected_serialize_len += sizeof(current_xattr->magic);
1821 current_xattr->name_length = strlen(xattr_name);
1822 current_xattr->name = bstrdup(xattr_name);
1824 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1826 current_xattr->value_length = *xattr_value_len;
1827 current_xattr->value = (char *)malloc(current_xattr->value_length);
1828 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
1830 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1833 * Protect ourself against things getting out of hand.
1835 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1836 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1837 jcr->last_fname, MAX_XATTR_STREAM);
1841 if (xattr_value_list == NULL) {
1842 xattr_value_list = New(alist(10, not_owned_by_alist));
1845 xattr_value_list->append(current_xattr);
1846 current_xattr = NULL;
1851 * If we found any xattr send them to the SD.
1853 if (xattr_count > 0) {
1855 * Serialize the datastream.
1857 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1858 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1860 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1866 * Send the datastream to the SD.
1868 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1872 if (current_xattr != NULL) {
1873 if (current_xattr->value != NULL) {
1874 free(current_xattr->value);
1876 if (current_xattr->name != NULL) {
1877 free(current_xattr->name);
1879 free(current_xattr);
1881 if (xattr_value_list != NULL) {
1882 xattr_drop_internal_table(xattr_value_list);
1884 free_pool_memory(xattrbuf);
1889 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr, int stream)
1891 char *bp, *xattrbuf = NULL;
1892 int32_t xattrbuf_size, cnt;
1893 xattr_t *current_xattr;
1894 alist *xattr_value_list;
1897 xattr_value_list = New(alist(10, not_owned_by_alist));
1899 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1900 xattr_drop_internal_table(xattr_value_list);
1901 return bxattr_exit_error;
1905 * See how big the propertylist must be.
1908 foreach_alist(current_xattr, xattr_value_list) {
1909 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
1912 xattrbuf = (char *)malloc(xattrbuf_size);
1915 * Add all value pairs to the proplist.
1919 foreach_alist(current_xattr, xattr_value_list) {
1920 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
1921 current_xattr->value, &bp);
1927 if (cnt != xattrbuf_size) {
1928 Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
1930 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
1936 * Restore the list of extended attributes on the file.
1938 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
1943 retval = bacl_exit_ok;
1946 Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
1947 jcr->last_fname, be.bstrerror());
1948 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
1949 jcr->last_fname, be.bstrerror());
1959 xattr_drop_internal_table(xattr_value_list);
1960 return bxattr_exit_ok;
1966 xattr_drop_internal_table(xattr_value_list);
1967 return bxattr_exit_error;
1971 * Function pointers to the build and parse function to use for these xattrs.
1973 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_xattr_streams;
1974 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = tru64_parse_xattr_streams;
1976 #elif defined(HAVE_SUN_OS)
1978 * Solaris extended attributes were introduced in Solaris 9
1981 * Solaris extensible attributes were introduced in OpenSolaris
1982 * by PSARC 2007/315 Solaris extensible attributes are also
1983 * sometimes called extended system attributes.
1985 * man fsattr(5) on Solaris gives a wealth of info. The most
1986 * important bits are:
1988 * Attributes are logically supported as files within the file
1989 * system. The file system is therefore augmented with an
1990 * orthogonal name space of file attributes. Any file (includ-
1991 * ing attribute files) can have an arbitrarily deep attribute
1992 * tree associated with it. Attribute values are accessed by
1993 * file descriptors obtained through a special attribute inter-
1994 * face. This logical view of "attributes as files" allows the
1995 * leveraging of existing file system interface functionality
1996 * to support the construction, deletion, and manipulation of
1999 * The special files "." and ".." retain their accustomed
2000 * semantics within the attribute hierarchy. The "." attribute
2001 * file refers to the current directory and the ".." attribute
2002 * file refers to the parent directory. The unnamed directory
2003 * at the head of each attribute tree is considered the "child"
2004 * of the file it is associated with and the ".." file refers
2005 * to the associated file. For any non-directory file with
2006 * attributes, the ".." entry in the unnamed directory refers
2007 * to a file that is not a directory.
2009 * Conceptually, the attribute model is fully general. Extended
2010 * attributes can be any type of file (doors, links, direc-
2011 * tories, and so forth) and can even have their own attributes
2012 * (fully recursive). As a result, the attributes associated
2013 * with a file could be an arbitrarily deep directory hierarchy
2014 * where each attribute could have an equally complex attribute
2015 * tree associated with it. Not all implementations are able
2016 * to, or want to, support the full model. Implementation are
2017 * therefore permitted to reject operations that are not sup-
2018 * ported. For example, the implementation for the UFS file
2019 * system allows only regular files as attributes (for example,
2020 * no sub-directories) and rejects attempts to place attributes
2023 * The following list details the operations that are rejected
2024 * in the current implementation:
2026 * link Any attempt to create links between
2027 * attribute and non-attribute space
2028 * is rejected to prevent security-
2029 * related or otherwise sensitive
2030 * attributes from being exposed, and
2031 * therefore manipulable, as regular
2034 * rename Any attempt to rename between
2035 * attribute and non-attribute space
2036 * is rejected to prevent an already
2037 * linked file from being renamed and
2038 * thereby circumventing the link res-
2041 * mkdir, symlink, mknod Any attempt to create a "non-
2042 * regular" file in attribute space is
2043 * rejected to reduce the functional-
2044 * ity, and therefore exposure and
2045 * risk, of the initial implementa-
2048 * The entire available name space has been allocated to "gen-
2049 * eral use" to bring the implementation in line with the NFSv4
2050 * draft standard [NFSv4]. That standard defines "named attri-
2051 * butes" (equivalent to Solaris Extended Attributes) with no
2052 * naming restrictions. All Sun applications making use of
2053 * opaque extended attributes will use the prefix "SUNW".
2056 #ifdef HAVE_SYS_ATTR_H
2057 #include <sys/attr.h>
2064 #ifdef HAVE_SYS_NVPAIR_H
2065 #include <sys/nvpair.h>
2068 #ifdef HAVE_SYS_ACL_H
2069 #include <sys/acl.h>
2072 #if !defined(HAVE_OPENAT) || \
2073 !defined(HAVE_UNLINKAT) || \
2074 !defined(HAVE_FCHOWNAT) || \
2075 !defined(HAVE_FUTIMESAT)
2076 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2080 * Define the supported XATTR streams for this OS
2082 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2083 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
2085 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
2086 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2089 * This code creates a temporary cache with entries for each xattr which has
2090 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2092 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2094 xattr_link_cache_entry_t *ptr;
2096 foreach_alist(ptr, jcr->xattr_data->link_cache) {
2097 if (ptr && ptr->inum == inum) {
2104 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2106 xattr_link_cache_entry_t *ptr;
2108 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2109 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
2111 bstrncpy(ptr->target, target, sizeof(ptr->target));
2112 jcr->xattr_data->link_cache->append(ptr);
2115 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2117 * This function returns true if a non default extended system attribute
2118 * list is associated with fd and returns false when an error has occured
2119 * or when only extended system attributes other than archive,
2120 * av_modified or crtime are set.
2122 * The function returns true for the following cases:
2124 * - any extended system attribute other than the default attributes
2125 * ('archive', 'av_modified' and 'crtime') is set
2126 * - nvlist has NULL name string
2127 * - nvpair has data type of 'nvlist'
2128 * - default data type.
2130 static bool solaris_has_non_transient_extensible_attributes(int fd)
2138 bool retval = false;
2140 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2145 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2146 name = nvpair_name(pair);
2149 fattr = name_to_attr(name);
2155 type = nvpair_type(pair);
2157 case DATA_TYPE_BOOLEAN_VALUE:
2158 if (nvpair_value_boolean_value(pair, &value) != 0) {
2161 if (value && fattr != F_ARCHIVE &&
2162 fattr != F_AV_MODIFIED) {
2167 case DATA_TYPE_UINT64_ARRAY:
2168 if (fattr != F_CRTIME) {
2173 case DATA_TYPE_NVLIST:
2181 if (response != NULL) {
2182 nvlist_free(response);
2186 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2188 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2190 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2191 * There is no need to store those acls as we already store the stat bits too.
2193 static bool acl_is_trivial(int count, aclent_t *entries)
2198 for (n = 0; n < count; n++) {
2200 if (!(ace->a_type == USER_OBJ ||
2201 ace->a_type == GROUP_OBJ ||
2202 ace->a_type == OTHER_OBJ ||
2203 ace->a_type == CLASS_OBJ))
2208 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2210 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2213 #ifdef HAVE_EXTENDED_ACL
2219 * See if this attribute has an ACL
2221 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2222 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2224 * See if there is a non trivial acl on the file.
2226 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2227 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2230 return bxattr_exit_ok;
2232 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2233 attrname, jcr->last_fname, be.bstrerror());
2234 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2235 attrname, jcr->last_fname, be.bstrerror());
2236 return bxattr_exit_error;
2241 #if defined(ACL_SID_FMT)
2243 * New format flag added in newer Solaris versions.
2245 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2247 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2248 #endif /* ACL_SID_FMT */
2250 *acl_text = acl_totext(aclp, flags);
2258 return bxattr_exit_ok;
2259 #else /* HAVE_EXTENDED_ACL */
2261 aclent_t *acls = NULL;
2265 * See if this attribute has an ACL
2268 n = facl(fd, GETACLCNT, 0, NULL);
2270 n = acl(attrname, GETACLCNT, 0, NULL);
2273 if (n >= MIN_ACL_ENTRIES) {
2274 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2275 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2276 acl(attrname, GETACL, n, acls) != n) {
2280 return bxattr_exit_ok;
2282 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2283 attrname, jcr->last_fname, be.bstrerror());
2284 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2285 attrname, jcr->last_fname, be.bstrerror());
2287 return bxattr_exit_error;
2292 * See if there is a non trivial acl on the file.
2294 if (!acl_is_trivial(n, acls)) {
2295 if ((*acl_text = acltotext(acls, n)) == NULL) {
2296 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2297 attrname, jcr->last_fname, be.bstrerror());
2298 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2299 attrname, jcr->last_fname, be.bstrerror());
2301 return bxattr_exit_error;
2311 return bxattr_exit_ok;
2312 #endif /* HAVE_EXTENDED_ACL */
2314 #else /* HAVE_ACL */
2315 return bxattr_exit_ok;
2316 #endif /* HAVE_ACL */
2320 * Forward declaration for recursive function call.
2322 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2325 * Save an extended or extensible attribute.
2326 * This is stored as an opaque stream of bytes with the following encoding:
2328 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2330 * or for a hardlinked or symlinked attribute
2332 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2334 * xattr_name can be a subpath relative to the file the xattr is on.
2335 * stat_buffer is the string representation of the stat struct.
2336 * acl_string is an acl text when a non trivial acl is set on the xattr.
2337 * actual_xattr_data is the content of the xattr file.
2339 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2340 const char *attrname, bool toplevel_hidden_dir, int stream)
2345 xattr_link_cache_entry_t *xlce;
2346 char target_attrname[PATH_MAX];
2347 char link_source[PATH_MAX];
2348 char *acl_text = NULL;
2349 char attribs[MAXSTRING];
2350 char buffer[XATTR_BUFSIZ];
2351 bxattr_exit_code retval = bxattr_exit_error;
2354 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2357 * Get the stats of the extended or extensible attribute.
2359 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2362 retval = bxattr_exit_ok;
2365 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2366 target_attrname, jcr->last_fname, be.bstrerror());
2367 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2368 target_attrname, jcr->last_fname, be.bstrerror());
2374 * Based on the filetype perform the correct action. We support most filetypes here, more
2375 * then the actual implementation on Solaris supports so some code may never get executed
2376 * due to limitations in the implementation.
2378 switch (st.st_mode & S_IFMT) {
2383 * Get any acl on the xattr.
2385 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2389 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2390 * Encode the stat struct into an ASCII representation.
2392 encode_stat(attribs, &st, 0, stream);
2393 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2394 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2398 * Get any acl on the xattr.
2400 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2404 * See if this is the toplevel_hidden_dir being saved.
2406 if (toplevel_hidden_dir) {
2408 * Save the data for later storage when we encounter a real xattr. We store the data
2409 * in the jcr->xattr_data->content buffer and flush that just before sending out the
2410 * first real xattr. Encode the stat struct into an ASCII representation and jump
2411 * out of the function.
2413 encode_stat(attribs, &st, 0, stream);
2414 cnt = bsnprintf(buffer, sizeof(buffer),
2416 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2417 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2418 jcr->xattr_data->content_length = cnt;
2422 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2423 * Encode the stat struct into an ASCII representation.
2425 encode_stat(attribs, &st, 0, stream);
2426 cnt = bsnprintf(buffer, sizeof(buffer),
2428 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2433 * If this is a hardlinked file check the inode cache for a hit.
2435 if (st.st_nlink > 1) {
2437 * See if the cache already knows this inode number.
2439 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2441 * Generate a xattr encoding with the reference to the target in there.
2443 encode_stat(attribs, &st, st.st_ino, stream);
2444 cnt = bsnprintf(buffer, sizeof(buffer),
2446 target_attrname, 0, attribs, 0, xlce->target, 0);
2447 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2448 jcr->xattr_data->content_length = cnt;
2449 retval = send_xattr_stream(jcr, stream);
2452 * For a hard linked file we are ready now, no need to recursively save the attributes.
2458 * Store this hard linked file in the cache.
2459 * Store the name relative to the top level xattr space.
2461 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2465 * Get any acl on the xattr.
2467 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2472 * Encode the stat struct into an ASCII representation.
2474 encode_stat(attribs, &st, 0, stream);
2475 cnt = bsnprintf(buffer, sizeof(buffer),
2477 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2480 * Open the extended or extensible attribute file.
2482 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2485 retval = bxattr_exit_ok;
2488 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2489 target_attrname, jcr->last_fname, be.bstrerror());
2490 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2491 target_attrname, jcr->last_fname, be.bstrerror());
2498 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2499 * Encode the stat struct into an ASCII representation.
2501 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2504 retval = bxattr_exit_ok;
2507 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2508 target_attrname, jcr->last_fname, be.bstrerror());
2509 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2510 target_attrname, jcr->last_fname, be.bstrerror());
2516 * Generate a xattr encoding with the reference to the target in there.
2518 encode_stat(attribs, &st, st.st_ino, stream);
2519 cnt = bsnprintf(buffer, sizeof(buffer),
2521 target_attrname, 0, attribs, 0, link_source, 0);
2522 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2523 jcr->xattr_data->content_length = cnt;
2524 retval = send_xattr_stream(jcr, stream);
2526 if (retval == bxattr_exit_ok) {
2527 jcr->xattr_data->nr_saved++;
2531 * For a soft linked file we are ready now, no need to recursively save the attributes.
2539 * See if this is the first real xattr being saved.
2540 * If it is save the toplevel_hidden_dir attributes first.
2541 * This is easy as its stored already in the jcr->xattr_data->content buffer.
2543 if (jcr->xattr_data->nr_saved == 0) {
2544 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2545 if (retval != bxattr_exit_ok) {
2548 jcr->xattr_data->nr_saved++;
2551 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2552 jcr->xattr_data->content_length = cnt;
2555 * Only dump the content of regular files.
2557 switch (st.st_mode & S_IFMT) {
2559 if (st.st_size > 0) {
2561 * Protect ourself against things getting out of hand.
2563 if (st.st_size >= MAX_XATTR_STREAM) {
2564 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2565 jcr->last_fname, MAX_XATTR_STREAM);
2569 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2570 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
2571 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
2572 jcr->xattr_data->content_length += cnt;
2576 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
2577 target_attrname, jcr->last_fname);
2578 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2579 target_attrname, jcr->last_fname);
2590 retval = send_xattr_stream(jcr, stream);
2591 if (retval == bxattr_exit_ok) {
2592 jcr->xattr_data->nr_saved++;
2597 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2598 * available on this extended attribute.
2601 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2604 * The recursive call could change our working dir so change back to the wanted workdir.
2606 if (fchdir(fd) < 0) {
2609 retval = bxattr_exit_ok;
2612 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2613 jcr->last_fname, be.bstrerror());
2614 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2615 jcr->last_fname, fd, be.bstrerror());
2622 if (acl_text != NULL) {
2631 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2634 int fd, filefd = -1, attrdirfd = -1;
2637 char current_xattr_namespace[PATH_MAX];
2638 bxattr_exit_code retval = bxattr_exit_error;
2642 * Determine what argument to use. Use attr_parent when set
2643 * (recursive call) or jcr->last_fname for first call. Also save
2644 * the current depth of the xattr_space we are in.
2648 if (xattr_namespace) {
2649 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2650 xattr_namespace, attr_parent);
2652 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2655 name = jcr->last_fname;
2656 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2660 * Open the file on which to save the xattrs read-only.
2662 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2665 retval = bxattr_exit_ok;
2668 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2669 jcr->last_fname, be.bstrerror());
2670 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2671 jcr->last_fname, be.bstrerror());
2677 * Open the xattr naming space.
2679 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2683 * Gentile way of the system saying this type of xattr layering is not supported.
2684 * Which is not problem we just forget about this this xattr.
2685 * But as this is not an error we return a positive return value.
2687 retval = bxattr_exit_ok;
2690 retval = bxattr_exit_ok;
2693 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2694 name, jcr->last_fname, be.bstrerror());
2695 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2696 name, jcr->last_fname, be.bstrerror());
2702 * We need to change into the attribute directory to determine if each of the
2703 * attributes should be saved.
2705 if (fchdir(attrdirfd) < 0) {
2706 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2707 jcr->last_fname, be.bstrerror());
2708 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2709 jcr->last_fname, attrdirfd, be.bstrerror());
2714 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2715 * else because the readdir returns "." entry after the extensible attr entry.
2716 * And as we want this entry before anything else we better just save its data.
2719 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2720 true, STREAM_XATTR_SOLARIS);
2722 if ((fd = dup(attrdirfd)) == -1 ||
2723 (dirp = fdopendir(fd)) == (DIR *)NULL) {
2724 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2725 jcr->last_fname, be.bstrerror());
2726 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
2727 jcr->last_fname, fd, be.bstrerror());
2733 * Walk the namespace.
2735 while ((dp = readdir(dirp)) != NULL) {
2737 * Skip only the toplevel . dir.
2739 if (!attr_parent && bstrcmp(dp->d_name, "."))
2743 * Skip all .. directories
2745 if (bstrcmp(dp->d_name, ".."))
2748 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2749 current_xattr_namespace, dp->d_name, jcr->last_fname);
2751 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2753 * We are not interested in read-only extensible attributes.
2755 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2756 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2757 current_xattr_namespace, dp->d_name, jcr->last_fname);
2763 * We are only interested in read-write extensible attributes
2764 * when they contain non-transient values.
2766 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2768 * Determine if there are non-transient system attributes at the toplevel.
2769 * We need to provide a fd to the open file.
2771 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2772 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2773 current_xattr_namespace, dp->d_name, jcr->last_fname);
2780 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2781 false, STREAM_XATTR_SOLARIS_SYS);
2784 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2789 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2790 false, STREAM_XATTR_SOLARIS);
2794 retval = bxattr_exit_ok;
2797 if (attrdirfd != -1)
2805 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
2807 #ifdef HAVE_EXTENDED_ACL
2812 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
2813 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
2815 return bxattr_exit_error;
2818 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
2819 acl_set(attrname, aclp) != 0) {
2820 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2821 attrname, jcr->last_fname, be.bstrerror());
2822 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2823 attrname, jcr->last_fname, be.bstrerror());
2824 return bxattr_exit_error;
2830 return bxattr_exit_ok;
2832 #else /* HAVE_EXTENDED_ACL */
2834 aclent_t *acls = NULL;
2837 acls = aclfromtext(acl_text, &n);
2839 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
2840 acl(attrname, SETACL, n, acls) != 0) {
2841 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2842 attrname, jcr->last_fname, be.bstrerror());
2843 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2844 attrname, jcr->last_fname, be.bstrerror());
2845 return bxattr_exit_error;
2852 return bxattr_exit_ok;
2854 #endif /* HAVE_EXTENDED_ACL */
2857 #endif /* HAVE_ACL */
2859 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
2861 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
2862 int used_bytes, total_bytes, cnt;
2863 char *bp, *target_attrname, *attribs;
2864 char *linked_target = NULL;
2865 char *acl_text = NULL;
2869 struct timeval times[2];
2870 bxattr_exit_code retval = bxattr_exit_error;
2874 * Parse the xattr stream. First the part that is the same for all xattrs.
2877 total_bytes = jcr->xattr_data->content_length;
2880 * The name of the target xattr has a leading / we are not interested
2881 * in that so skip it when decoding the string. We always start a the /
2882 * of the xattr space anyway.
2884 target_attrname = jcr->xattr_data->content + 1;
2885 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
2886 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2892 * Open the file on which to restore the xattrs read-only.
2894 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
2895 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2896 jcr->last_fname, be.bstrerror());
2897 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2898 jcr->last_fname, be.bstrerror());
2903 * Open the xattr naming space and make it the current working dir.
2905 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2906 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
2907 jcr->last_fname, be.bstrerror());
2908 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
2909 jcr->last_fname, be.bstrerror());
2913 if (fchdir(attrdirfd) < 0) {
2914 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2915 jcr->last_fname, be.bstrerror());
2916 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2917 jcr->last_fname, attrdirfd, be.bstrerror());
2922 * Try to open the correct xattr subdir based on the target_attrname given.
2923 * e.g. check if its a subdir attrname. Each / in the string makes us go
2926 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2929 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2930 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2931 target_attrname, jcr->last_fname, be.bstrerror());
2932 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2933 target_attrname, jcr->last_fname, be.bstrerror());
2941 * Open the xattr naming space.
2943 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2944 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2945 target_attrname, jcr->last_fname, be.bstrerror());
2946 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2947 target_attrname, jcr->last_fname, be.bstrerror());
2955 * Make the xattr space our current workingdir.
2957 if (fchdir(attrdirfd) < 0) {
2958 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2959 target_attrname, jcr->last_fname, be.bstrerror());
2960 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2961 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2965 target_attrname = ++bp;
2969 * Decode the attributes from the stream.
2971 decode_stat(attribs, &st, &inum);
2974 * Decode the next field (acl_text).
2976 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2977 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2983 * Based on the filetype perform the correct action. We support most filetypes here, more
2984 * then the actual implementation on Solaris supports so some code may never get executed
2985 * due to limitations in the implementation.
2987 switch (st.st_mode & S_IFMT) {
2990 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2992 unlinkat(attrdirfd, target_attrname, 0);
2993 if (mkfifo(target_attrname, st.st_mode) < 0) {
2994 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
2995 target_attrname, jcr->last_fname, be.bstrerror());
2996 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
2997 target_attrname, jcr->last_fname, be.bstrerror());
3004 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3006 unlinkat(attrdirfd, target_attrname, 0);
3007 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3008 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3009 target_attrname, jcr->last_fname, be.bstrerror());
3010 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3011 target_attrname, jcr->last_fname, be.bstrerror());
3017 * If its not the hidden_dir create the entry.
3018 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3020 if (!bstrcmp(target_attrname, ".")) {
3021 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3022 if (mkdir(target_attrname, st.st_mode) < 0) {
3023 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3024 target_attrname, jcr->last_fname, be.bstrerror());
3025 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3026 target_attrname, jcr->last_fname, be.bstrerror());
3033 * See if this is a hard linked file. e.g. inum != 0
3038 unlinkat(attrdirfd, target_attrname, 0);
3039 if (link(linked_target, target_attrname) < 0) {
3040 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3041 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3042 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3043 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3048 * Successfully restored xattr.
3050 retval = bxattr_exit_ok;
3053 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3054 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
3058 if (used_bytes < (total_bytes - 1))
3062 * Restore the actual xattr.
3064 if (!is_extensible) {
3065 unlinkat(attrdirfd, target_attrname, 0);
3068 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3069 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3070 target_attrname, jcr->last_fname, be.bstrerror());
3071 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3072 target_attrname, jcr->last_fname, be.bstrerror());
3078 * Restore the actual data.
3080 if (st.st_size > 0) {
3081 used_bytes = (data - jcr->xattr_data->content);
3082 cnt = total_bytes - used_bytes;
3085 * Do a sanity check, the st.st_size should be the same as the number of bytes
3086 * we have available as data of the stream.
3088 if (cnt != st.st_size) {
3089 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3090 target_attrname, jcr->last_fname);
3091 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3092 target_attrname, jcr->last_fname);
3097 cnt = write(attrfd, data, cnt);
3099 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3100 target_attrname, jcr->last_fname, be.bstrerror());
3101 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3102 target_attrname, jcr->last_fname, be.bstrerror());
3108 cnt = total_bytes - used_bytes;
3114 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3118 if (symlink(linked_target, target_attrname) < 0) {
3119 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3120 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3121 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3122 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3127 * Successfully restored xattr.
3129 retval = bxattr_exit_ok;
3136 * Restore owner and acl for non extensible attributes.
3138 if (!is_extensible) {
3139 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3143 * Gentile way of the system saying this type of xattr layering is not supported.
3144 * But as this is not an error we return a positive return value.
3146 retval = bxattr_exit_ok;
3149 retval = bxattr_exit_ok;
3152 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3153 target_attrname, jcr->last_fname, be.bstrerror());
3154 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3155 target_attrname, jcr->last_fname, be.bstrerror());
3162 if (acl_text && *acl_text)
3163 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3165 #endif /* HAVE_ACL */
3168 * For a non extensible attribute restore access and modification time on the xattr.
3170 if (!is_extensible) {
3171 times[0].tv_sec = st.st_atime;
3172 times[0].tv_usec = 0;
3173 times[1].tv_sec = st.st_mtime;
3174 times[1].tv_usec = 0;
3176 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3177 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3178 target_attrname, jcr->last_fname, be.bstrerror());
3179 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3180 target_attrname, jcr->last_fname, be.bstrerror());
3186 * Successfully restored xattr.
3188 retval = bxattr_exit_ok;
3192 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3194 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3201 if (attrdirfd != -1) {
3210 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3213 bxattr_exit_code retval = bxattr_exit_ok;
3216 * First see if extended attributes or extensible attributes are present.
3217 * If not just pretend things went ok.
3219 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3220 jcr->xattr_data->nr_saved = 0;
3221 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
3224 * As we change the cwd in the save function save the current cwd
3225 * for restore after return from the solaris_save_xattrs function.
3227 getcwd(cwd, sizeof(cwd));
3228 retval = solaris_save_xattrs(jcr, NULL, NULL);
3230 delete jcr->xattr_data->link_cache;
3231 jcr->xattr_data->link_cache = NULL;
3236 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
3239 bool is_extensible = false;
3240 bxattr_exit_code retval;
3243 * First make sure we can restore xattr on the filesystem.
3246 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3247 case STREAM_XATTR_SOLARIS_SYS:
3248 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3249 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
3250 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3252 return bxattr_exit_error;
3255 is_extensible = true;
3258 case STREAM_XATTR_SOLARIS:
3259 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3260 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
3261 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3263 return bxattr_exit_error;
3267 return bxattr_exit_error;
3271 * As we change the cwd in the restore function save the current cwd
3272 * for restore after return from the solaris_restore_xattrs function.
3274 getcwd(cwd, sizeof(cwd));
3275 retval = solaris_restore_xattrs(jcr, is_extensible);
3282 * Function pointers to the build and parse function to use for these xattrs.
3284 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
3285 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
3287 #endif /* defined(HAVE_SUN_OS) */
3290 * Entry points when compiled with support for XATTRs on a supported platform.
3292 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3294 if (os_build_xattr_streams) {
3295 return (*os_build_xattr_streams)(jcr, ff_pkt);
3297 return bxattr_exit_error;
3300 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
3304 if (os_parse_xattr_streams) {
3306 * See if we can parse this stream, and ifso give it a try.
3308 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3309 if (os_default_xattr_streams[cnt] == stream) {
3310 return (*os_parse_xattr_streams)(jcr, stream);
3315 * Issue a warning and discard the message. But pretend the restore was ok.
3317 Jmsg2(jcr, M_WARNING, 0,
3318 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3319 jcr->last_fname, stream);
3320 return bxattr_exit_error;