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 * - IRIX (Extended Attributes)
38 * - Linux (Extended Attributes)
39 * - NetBSD (Extended Attributes)
40 * - FreeBSD (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)
49 * Written by Marco van Wieringen, November MMVIII
56 #if !defined(HAVE_XATTR)
58 * Entry points when compiled without support for XATTRs or on an unsupported platform.
60 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
62 return bxattr_exit_fatal;
65 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
67 return bxattr_exit_fatal;
71 * Send a XATTR stream to the SD.
73 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
75 BSOCK *sd = jcr->store_bsock;
77 #ifdef FD_NO_SEND_TEST
78 return bxattr_exit_ok;
84 if (jcr->xattr_data->content_length <= 0) {
85 return bxattr_exit_ok;
91 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
92 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
94 return bxattr_exit_fatal;
98 * Send the buffer to the storage deamon
100 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
102 sd->msg = jcr->xattr_data->content;
103 sd->msglen = jcr->xattr_data->content_length;
107 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
109 return bxattr_exit_fatal;
112 jcr->JobBytes += sd->msglen;
114 if (!sd->signal(BNET_EOD)) {
115 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
117 return bxattr_exit_fatal;
119 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
120 return bxattr_exit_ok;
124 * First some generic functions for OSes that use the same xattr encoding scheme.
125 * Currently for all OSes except for Solaris.
127 #if !defined(HAVE_SUN_OS)
128 static void xattr_drop_internal_table(alist *xattr_value_list)
130 xattr_t *current_xattr;
133 * Walk the list of xattrs and free allocated memory on traversing.
135 foreach_alist(current_xattr, xattr_value_list) {
137 * See if we can shortcut.
139 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
142 free(current_xattr->name);
144 if (current_xattr->value_length > 0)
145 free(current_xattr->value);
150 delete xattr_value_list;
154 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
155 * which encodes one or more xattr_t structures.
157 * The Serialized stream consists of the following elements:
158 * magic - A magic string which makes it easy to detect any binary incompatabilites
159 * name_length - The length of the following xattr name
160 * name - The name of the extended attribute
161 * value_length - The length of the following xattr data
162 * value - The actual content of the extended attribute
164 * This is repeated 1 or more times.
167 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, alist *xattr_value_list)
169 xattr_t *current_xattr;
173 * Make sure the serialized stream fits in the poolmem buffer.
174 * We allocate some more to be sure the stream is gonna fit.
176 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
177 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
180 * Walk the list of xattrs and serialize the data.
182 foreach_alist(current_xattr, xattr_value_list) {
184 * See if we can shortcut.
186 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
189 ser_uint32(current_xattr->magic);
190 ser_uint32(current_xattr->name_length);
191 ser_bytes(current_xattr->name, current_xattr->name_length);
193 ser_uint32(current_xattr->value_length);
194 if (current_xattr->value_length > 0 && current_xattr->value) {
195 ser_bytes(current_xattr->value, current_xattr->value_length);
197 Dmsg3(100, "Backup xattr named %s, value %*s\n",
198 current_xattr->name, current_xattr->value, current_xattr->value);
200 Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
204 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
205 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
207 return jcr->xattr_data->content_length;
210 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
213 xattr_t *current_xattr;
214 bxattr_exit_code retval = bxattr_exit_ok;
217 * Parse the stream and call restore_xattr_on_file for each extended attribute.
219 * Start unserializing the data. We keep on looping while we have not
220 * unserialized all bytes in the stream.
222 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
223 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
225 * First make sure the magic is present. This way we can easily catch corruption.
226 * Any missing MAGIC is fatal we do NOT try to continue.
229 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
230 unser_uint32(current_xattr->magic);
231 if (current_xattr->magic != XATTR_MAGIC) {
232 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
234 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
237 return bxattr_exit_error;
241 * Decode the valuepair. First decode the length of the name.
243 unser_uint32(current_xattr->name_length);
244 if (current_xattr->name_length == 0) {
245 Mmsg1(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
247 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
250 return bxattr_exit_error;
254 * Allocate room for the name and decode its content.
256 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
257 unser_bytes(current_xattr->name, current_xattr->name_length);
260 * The xattr_name needs to be null terminated.
262 current_xattr->name[current_xattr->name_length] = '\0';
265 * Decode the value length.
267 unser_uint32(current_xattr->value_length);
269 if (current_xattr->value_length > 0) {
271 * Allocate room for the value and decode its content.
273 current_xattr->value = (char *)malloc(current_xattr->value_length);
274 unser_bytes(current_xattr->value, current_xattr->value_length);
276 Dmsg3(100, "Restoring xattr named %s, value %*s\n",
277 current_xattr->name, current_xattr->value, current_xattr->value);
279 current_xattr->value = NULL;
280 Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
283 xattr_value_list->append(current_xattr);
286 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
292 * This is a supported OS, See what kind of interface we should use.
294 #if defined(HAVE_AIX_OS)
296 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
297 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
298 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
299 #error "Missing full support for the Extended Attributes (EA) functions."
305 #error "Missing sys/ea.h header file"
309 * Define the supported XATTR streams for this OS
311 static int os_default_xattr_streams[1] = { STREAM_XATTR_AIX };
314 * Fallback to the non l-functions when those are not available.
316 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
319 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
322 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
323 #define llistea listea
326 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
329 char *xattr_list, *bp;
330 int cnt, xattr_count = 0;
331 uint32_t name_length;
332 int32_t xattr_list_len,
334 uint32_t expected_serialize_len = 0;
335 xattr_t *current_xattr = NULL;
336 alist *xattr_value_list = NULL;
337 bxattr_exit_code retval = bxattr_exit_error;
341 * First get the length of the available list with extended attributes.
343 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
344 switch (xattr_list_len) {
350 return bxattr_exit_ok;
352 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
353 jcr->last_fname, be.bstrerror());
354 Dmsg2(100, "llistea error file=%s ERR=%s\n",
355 jcr->last_fname, be.bstrerror());
356 return bxattr_exit_error;
360 return bxattr_exit_ok;
366 * Allocate room for the extented attribute list.
368 xattr_list = (char *)malloc(xattr_list_len + 1);
369 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
372 * Get the actual list of extended attributes names for a file.
374 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
375 switch (xattr_list_len) {
381 retval = bxattr_exit_ok;
384 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
385 jcr->last_fname, be.bstrerror());
386 Dmsg2(100, "llistea error file=%s ERR=%s\n",
387 jcr->last_fname, be.bstrerror());
394 xattr_list[xattr_list_len] = '\0';
396 xattr_value_list = New(alist(10, not_owned_by_alist));
399 * Walk the list of extended attributes names and retrieve the data.
400 * We already count the bytes needed for serializing the stream later on.
403 while ((bp - xattr_list) + 1 < xattr_list_len) {
407 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
413 name_length = strlen(bp);
414 if (skip_xattr || name_length == 0) {
415 bp = strchr(bp, '\0') + 1;
416 Dmsg1(100, "Skipping xattr named %s\n", current_xattr->name);
421 * Each xattr valuepair starts with a magic so we can parse it easier.
423 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
424 current_xattr->magic = XATTR_MAGIC;
425 expected_serialize_len += sizeof(current_xattr->magic);
428 * Allocate space for storing the name.
430 current_xattr->name_length = name_length;
431 current_xattr->name = (char *)malloc(current_xattr->name_length);
432 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
434 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
437 * First see how long the value is for the extended attribute.
439 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
440 switch (xattr_value_len) {
446 retval = bxattr_exit_ok;
449 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
450 jcr->last_fname, be.bstrerror());
451 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
452 jcr->last_fname, be.bstrerror());
457 current_xattr->value = NULL;
458 current_xattr->value_length = 0;
459 expected_serialize_len += sizeof(current_xattr->value_length);
463 * Allocate space for storing the value.
465 current_xattr->value = (char *)malloc(xattr_value_len);
466 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
468 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
469 if (xattr_value_len < 0) {
474 retval = bxattr_exit_ok;
477 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
478 jcr->last_fname, be.bstrerror());
479 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
480 jcr->last_fname, be.bstrerror());
485 * Store the actual length of the value.
487 current_xattr->value_length = xattr_value_len;
488 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
491 * Protect ourself against things getting out of hand.
493 if (expected_serialize_len >= MAX_XATTR_STREAM) {
494 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
495 jcr->last_fname, MAX_XATTR_STREAM);
500 xattr_value_list->append(current_xattr);
501 current_xattr = NULL;
503 bp = strchr(bp, '\0') + 1;
508 xattr_list = (char *)NULL;
511 * If we found any xattr send them to the SD.
513 if (xattr_count > 0) {
515 * Serialize the datastream.
517 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
518 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
520 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
525 xattr_drop_internal_table(xattr_value_list);
528 * Send the datastream to the SD.
530 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
532 xattr_drop_internal_table(xattr_value_list);
534 return bxattr_exit_ok;
538 if (current_xattr != NULL) {
539 if (current_xattr->value != NULL) {
540 free(current_xattr->value);
542 if (current_xattr->name != NULL) {
543 free(current_xattr->name);
547 if (xattr_list != NULL) {
550 if (xattr_value_list != NULL) {
551 xattr_drop_internal_table(xattr_value_list);
556 static bxattr_exit_code aix_xattr_parse_streams(JCR *jcr, int stream)
558 xattr_t *current_xattr;
559 alist *xattr_value_list;
562 xattr_value_list = New(alist(10, not_owned_by_alist));
564 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
565 xattr_drop_internal_table(xattr_value_list);
566 return bxattr_exit_error;
569 foreach_alist(current_xattr, xattr_value_list) {
570 if (lsetea(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
577 Mmsg2(jcr->errmsg, _("lsetea error on file \"%s\": ERR=%s\n"),
578 jcr->last_fname, be.bstrerror());
579 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
580 jcr->last_fname, be.bstrerror());
586 xattr_drop_internal_table(xattr_value_list);
587 return bxattr_exit_ok;
590 xattr_drop_internal_table(xattr_value_list);
591 return bxattr_exit_error;
595 * Function pointers to the build and parse function to use for these xattrs.
597 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_xattr_build_streams;
598 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = aix_xattr_parse_streams;
600 #elif defined(HAVE_IRIX_OS)
603 * Define the supported XATTR streams for this OS
605 static int os_default_xattr_streams[1] = { STREAM_XATTR_IRIX };
606 static const char *xattr_acl_skiplist[1] = { NULL };
607 static const char *xattr_skiplist[1] = { NULL };
609 struct xattr_naming_space {
614 static xattr_naming_space xattr_naming_spaces[] = {
615 { "user.", ATTR_DONTFOLLOW },
616 { "root.", ATTR_ROOT | ATTR_DONTFOLLOW },
620 static bxattr_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
622 int cnt, xattr_count = 0;
623 attrlist_cursor_t cursor;
624 attrlist_t *attrlist;
625 attrlist_ent_t *attrlist_ent;
626 xattr_t *current_xattr = NULL;
627 alist *xattr_value_list = NULL;
628 uint32_t expected_serialize_len = 0;
629 bxattr_exit_code retval = bxattr_exit_error;
630 POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
633 xattr_value_list = New(alist(10, not_owned_by_alist));
635 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
636 memset(cursor, 0, sizeof(attrlist_cursor_t));
638 if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
639 xattr_naming_spaces[cnt].flags, &cursor) != 0) {
642 retval = bxattr_exit_ok;
645 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
646 jcr->last_fname, be.bstrerror());
647 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
648 jcr->last_fname, be.bstrerror());
653 attrlist = (attrlist_t *)xattrbuf;
656 * Walk the available attributes.
658 for (cnt = 0; cnt < attrlist->al_count; cnt++) {
659 attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
662 * Each xattr valuepair starts with a magic so we can parse it easier.
664 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
665 current_xattr->magic = XATTR_MAGIC;
666 expected_serialize_len += sizeof(current_xattr->magic);
669 * Allocate space for storing the name.
670 * We store the name as <naming_space_name><xattr_name>
672 current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) + strlen(attrlist_ent->a_name) + 1;
673 current_xattr->name = (char *)malloc(current_xattr->name_length);
674 bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
675 xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
677 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
679 current_xattr->value_length = attrlist_ent->a_valuelen;
680 current_xattr->value = (char *)malloc(current_xattr->value_length);
683 * Retrieve the actual value of the xattr.
685 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
686 current_xattr->value_length, xattr_naming_spaces[cnt].flags) != 0) {
690 retval = bxattr_exit_ok;
694 * The buffer for the xattr isn't big enough. the value of
695 * current_xattr->value_length is updated with the actual size
696 * of the xattr. So we free the old buffer and create a new one
699 free(current_xattr->value);
700 current_xattr->value = (char *)malloc(current_xattr->value_length);
701 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
702 current_xattr->value_length, xattr_naming_spaces[cnt].flags) != 0) {
706 retval = bxattr_exit_ok;
709 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
710 jcr->last_fname, be.bstrerror());
711 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
712 jcr->last_fname, be.bstrerror());
718 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
719 jcr->last_fname, be.bstrerror());
720 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
721 jcr->last_fname, be.bstrerror());
726 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
729 * Protect ourself against things getting out of hand.
731 if (expected_serialize_len >= MAX_XATTR_STREAM) {
732 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
733 jcr->last_fname, MAX_XATTR_STREAM);
737 xattr_value_list->append(current_xattr);
738 current_xattr = NULL;
743 * See if there are more attributes available for a next run of attr_list.
745 if (attrlist->al_more == 0) {
752 * If we found any xattr send them to the SD.
754 if (xattr_count > 0) {
756 * Serialize the datastream.
758 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
759 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
761 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
766 xattr_drop_internal_table(xattr_value_list);
769 * Send the datastream to the SD.
771 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
773 xattr_drop_internal_table(xattr_value_list);
775 return bxattr_exit_ok;
779 if (current_xattr != NULL) {
780 if (current_xattr->value != NULL) {
781 free(current_xattr->value);
783 if (current_xattr->name != NULL) {
784 free(current_xattr->name);
788 free_pool_memory(xattrbuf);
790 if (xattr_value_list != NULL) {
791 xattr_drop_internal_table(xattr_value_list);
796 static bxattr_exit_code irix_xattr_parse_streams(JCR *jcr, int stream)
799 int cnt, cmp_size, name_space_index;
800 xattr_t *current_xattr;
801 alist *xattr_value_list;
804 xattr_value_list = New(alist(10, not_owned_by_alist));
806 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
807 xattr_drop_internal_table(xattr_value_list);
808 return bxattr_exit_error;
811 foreach_alist(current_xattr, xattr_value_list) {
813 * See to what namingspace this xattr belongs to.
815 name_space_index = 0;
816 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
817 cmp_size = strlen(xattr_naming_spaces[cnt].name);
818 if (!strncasecmp(current_xattr->name,
819 xattr_naming_spaces[cnt].name,
821 name_space_index = cnt;
827 * If we got a xattr that doesn't belong to ant valid namespace complain.
829 if (name_space_index == 0) {
830 Mmsg2(jcr->errmsg, _("Received illegal xattr named %s on file \"%s\"\n"),
831 current_xattr->name, jcr->last_fname);
832 Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
833 current_xattr->name, jcr->last_fname);
838 * Restore the xattr first try to create the attribute from scratch.
840 flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
841 bp = strchr(current_xattr->name, '.');
842 if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
843 current_xattr->value_len, flags) != 0) {
846 retval = bxattr_exit_ok;
850 * The xattr already exists we need to replace it.
852 flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
853 if (attr_set(jcr->last_fname, bp, current_xattr->value,
854 current_xattr->value_len, flags) != 0) {
857 retval = bxattr_exit_ok;
860 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
861 jcr->last_fname, be.bstrerror());
862 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
863 jcr->last_fname, be.bstrerror());
869 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
870 jcr->last_fname, be.bstrerror());
871 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
872 jcr->last_fname, be.bstrerror());
878 xattr_drop_internal_table(xattr_value_list);
879 return bxattr_exit_ok;
882 xattr_drop_internal_table(xattr_value_list);
883 return bxattr_exit_error;
887 * Function pointers to the build and parse function to use for these xattrs.
889 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = irix_xattr_build_streams;
890 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = irix_xattr_parse_streams;
892 #elif defined(HAVE_DARWIN_OS) || \
893 defined(HAVE_LINUX_OS)
895 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
896 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
897 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
898 #error "Missing full support for the XATTR functions."
901 #ifdef HAVE_SYS_XATTR_H
902 #include <sys/xattr.h>
904 #error "Missing sys/xattr.h header file"
908 * Define the supported XATTR streams for this OS
910 #if defined(HAVE_DARWIN_OS)
911 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
912 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
913 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
914 #elif defined(HAVE_LINUX_OS)
915 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
916 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
917 static const char *xattr_skiplist[1] = { NULL };
921 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
922 * listxattr, getxattr and setxattr with an extra options argument
923 * which mimics the l variants of the functions when we specify
924 * XATTR_NOFOLLOW as the options value.
926 #if defined(HAVE_DARWIN_OS)
927 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
928 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
929 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
932 * Fallback to the non l-functions when those are not available.
934 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
935 #define lgetxattr getxattr
937 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
938 #define lsetxattr setxattr
940 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
941 #define llistxattr listxattr
945 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
948 char *xattr_list, *bp;
949 int cnt, xattr_count = 0;
950 int32_t xattr_list_len,
952 uint32_t expected_serialize_len = 0;
953 xattr_t *current_xattr = NULL;
954 alist *xattr_value_list = NULL;
955 bxattr_exit_code retval = bxattr_exit_error;
959 * First get the length of the available list with extended attributes.
961 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
962 switch (xattr_list_len) {
967 return bxattr_exit_ok;
969 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
970 jcr->last_fname, be.bstrerror());
971 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
972 jcr->last_fname, be.bstrerror());
973 return bxattr_exit_error;
977 return bxattr_exit_ok;
983 * Allocate room for the extented attribute list.
985 xattr_list = (char *)malloc(xattr_list_len + 1);
986 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
989 * Get the actual list of extended attributes names for a file.
991 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
992 switch (xattr_list_len) {
997 retval = bxattr_exit_ok;
1000 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
1001 jcr->last_fname, be.bstrerror());
1002 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1003 jcr->last_fname, be.bstrerror());
1010 xattr_list[xattr_list_len] = '\0';
1012 xattr_value_list = New(alist(10, not_owned_by_alist));
1015 * Walk the list of extended attributes names and retrieve the data.
1016 * We already count the bytes needed for serializing the stream later on.
1019 while ((bp - xattr_list) + 1 < xattr_list_len) {
1024 * On some OSes you also get the acls in the extented attribute list.
1025 * So we check if we are already backing up acls and if we do we
1026 * don't store the extended attribute with the same info.
1028 if (ff_pkt->flags & FO_ACL) {
1029 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1030 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1038 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1041 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1042 if (bstrcmp(bp, xattr_skiplist[cnt])) {
1049 name_len = strlen(bp);
1050 if (skip_xattr || name_len == 0) {
1051 bp = strchr(bp, '\0') + 1;
1052 Dmsg1(100, "Skipping xattr named %s\n", current_xattr->name);
1057 * Each xattr valuepair starts with a magic so we can parse it easier.
1059 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1060 current_xattr->magic = XATTR_MAGIC;
1061 expected_serialize_len += sizeof(current_xattr->magic);
1064 * Allocate space for storing the name.
1066 current_xattr->name_length = name_len;
1067 current_xattr->name = (char *)malloc(current_xattr->name_length);
1068 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
1070 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1073 * First see how long the value is for the extended attribute.
1075 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1076 switch (xattr_value_len) {
1081 retval = bxattr_exit_ok;
1084 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1085 jcr->last_fname, be.bstrerror());
1086 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1087 jcr->last_fname, be.bstrerror());
1092 current_xattr->value = NULL;
1093 current_xattr->value_length = 0;
1094 expected_serialize_len += sizeof(current_xattr->value_length);
1098 * Allocate space for storing the value.
1100 current_xattr->value = (char *)malloc(xattr_value_len);
1101 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1103 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1104 if (xattr_value_len < 0) {
1108 retval = bxattr_exit_ok;
1111 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1112 jcr->last_fname, be.bstrerror());
1113 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1114 jcr->last_fname, be.bstrerror());
1119 * Store the actual length of the value.
1121 current_xattr->value_length = xattr_value_len;
1122 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1125 * Protect ourself against things getting out of hand.
1127 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1128 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1129 jcr->last_fname, MAX_XATTR_STREAM);
1134 xattr_value_list->append(current_xattr);
1135 current_xattr = NULL;
1137 bp = strchr(bp, '\0') + 1;
1142 xattr_list = (char *)NULL;
1145 * If we found any xattr send them to the SD.
1147 if (xattr_count > 0) {
1149 * Serialize the datastream.
1151 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1152 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1154 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1159 xattr_drop_internal_table(xattr_value_list);
1162 * Send the datastream to the SD.
1164 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
1166 xattr_drop_internal_table(xattr_value_list);
1168 return bxattr_exit_ok;
1172 if (current_xattr != NULL) {
1173 if (current_xattr->value != NULL) {
1174 free(current_xattr->value);
1176 if (current_xattr->name != NULL) {
1177 free(current_xattr->name);
1179 free(current_xattr);
1181 if (xattr_list != NULL) {
1184 if (xattr_value_list != NULL) {
1185 xattr_drop_internal_table(xattr_value_list);
1190 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
1192 xattr_t *current_xattr;
1193 alist *xattr_value_list;
1196 xattr_value_list = New(alist(10, not_owned_by_alist));
1198 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1199 xattr_drop_internal_table(xattr_value_list);
1200 return bxattr_exit_error;
1203 foreach_alist(current_xattr, xattr_value_list) {
1204 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1210 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
1211 jcr->last_fname, be.bstrerror());
1212 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1213 jcr->last_fname, be.bstrerror());
1219 xattr_drop_internal_table(xattr_value_list);
1220 return bxattr_exit_ok;
1223 xattr_drop_internal_table(xattr_value_list);
1224 return bxattr_exit_error;
1228 * Function pointers to the build and parse function to use for these xattrs.
1230 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
1231 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
1233 #elif defined(HAVE_FREEBSD_OS) || \
1234 defined(HAVE_NETBSD_OS) || \
1235 defined(HAVE_OPENBSD_OS)
1237 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1238 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1239 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1240 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1241 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1242 #error "Missing full support for the extattr functions."
1245 #ifdef HAVE_SYS_EXTATTR_H
1246 #include <sys/extattr.h>
1248 #error "Missing sys/extattr.h header file"
1251 #ifdef HAVE_LIBUTIL_H
1252 #include <libutil.h>
1255 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1256 #define extattr_get_link extattr_get_file
1258 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1259 #define extattr_set_link extattr_set_file
1261 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1262 #define extattr_list_link extattr_list_file
1265 #if defined(HAVE_FREEBSD_OS)
1266 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
1267 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1268 static const char *xattr_acl_skiplist[2] = { "system.posix1e.acl_access", NULL };
1269 static const char *xattr_skiplist[1] = { NULL };
1270 #elif defined(HAVE_NETBSD_OS)
1271 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
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 };
1275 #elif defined(HAVE_OPENBSD_OS)
1276 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
1277 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1278 static const char *xattr_acl_skiplist[1] = { NULL };
1279 static const char *xattr_skiplist[1] = { NULL };
1282 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1286 int cnt, index, xattr_count = 0;
1287 int32_t xattr_list_len,
1289 uint32_t expected_serialize_len = 0;
1290 unsigned int namespace_index;
1292 char *current_attrnamespace = NULL;
1293 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1294 xattr_t *current_xattr = NULL;
1295 alist *xattr_value_list = NULL;
1296 bxattr_exit_code retval = bxattr_exit_error;
1299 xattr_value_list = New(alist(10, not_owned_by_alist));
1302 * Loop over all available xattr namespaces.
1304 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
1305 attrnamespace = os_default_xattr_namespaces[namespace_index];
1308 * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
1309 * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
1311 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1312 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
1313 attrnamespace, jcr->last_fname);
1314 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1315 attrnamespace, jcr->last_fname);
1320 * First get the length of the available list with extended attributes.
1321 * If we get EPERM on system namespace, don't return error.
1322 * This is expected for normal users trying to archive the system
1323 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1324 * they've decided to return EOPNOTSUPP instead.
1326 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1327 switch (xattr_list_len) {
1331 retval = bxattr_exit_ok;
1333 #if defined(EOPNOTSUPP)
1337 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1338 actuallyfree(current_attrnamespace);
1339 current_attrnamespace = NULL;
1346 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1347 jcr->last_fname, be.bstrerror());
1348 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1349 jcr->last_fname, be.bstrerror());
1360 * Allocate room for the extented attribute list.
1362 xattr_list = (char *)malloc(xattr_list_len + 1);
1363 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
1366 * Get the actual list of extended attributes names for a file.
1368 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
1369 switch (xattr_list_len) {
1373 retval = bxattr_exit_ok;
1376 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1377 jcr->last_fname, be.bstrerror());
1378 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1379 jcr->last_fname, be.bstrerror());
1386 xattr_list[xattr_list_len] = '\0';
1389 * Walk the list of extended attributes names and retrieve the data.
1390 * We already count the bytes needed for serializing the stream later on.
1392 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1396 * Print the current name into the buffer as its not null terminated we need to
1397 * use the length encoded in the string for copying only the needed bytes.
1399 cnt = xattr_list[index];
1400 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1401 cnt = ((int)sizeof(current_attrname) - 1);
1403 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1404 current_attrname[cnt] = '\0';
1407 * First make a xattr tuple of the current namespace and the name of the xattr.
1408 * e.g. something like user.<attrname> or system.<attrname>
1410 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
1413 * On some OSes you also get the acls in the extented attribute list.
1414 * So we check if we are already backing up acls and if we do we
1415 * don't store the extended attribute with the same info.
1417 if (ff_pkt->flags & FO_ACL) {
1418 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1419 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1427 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1430 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1431 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1439 Dmsg1(100, "Skipping xattr named %s\n", current_xattr->name);
1444 * Each xattr valuepair starts with a magic so we can parse it easier.
1446 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1447 current_xattr->magic = XATTR_MAGIC;
1448 expected_serialize_len += sizeof(current_xattr->magic);
1451 * Allocate space for storing the name.
1453 current_xattr->name_length = strlen(current_attrtuple);
1454 current_xattr->name = (char *)malloc(current_xattr->name_length);
1455 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
1457 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1460 * First see how long the value is for the extended attribute.
1462 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
1463 switch (xattr_value_len) {
1467 retval = bxattr_exit_ok;
1470 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1471 jcr->last_fname, be.bstrerror());
1472 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1473 jcr->last_fname, be.bstrerror());
1478 current_xattr->value = NULL;
1479 current_xattr->value_length = 0;
1480 expected_serialize_len += sizeof(current_xattr->value_length);
1484 * Allocate space for storing the value.
1486 current_xattr->value = (char *)malloc(xattr_value_len);
1487 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1489 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
1490 if (xattr_value_len < 0) {
1493 retval = bxattr_exit_ok;
1496 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1497 jcr->last_fname, be.bstrerror());
1498 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1499 jcr->last_fname, be.bstrerror());
1505 * Store the actual length of the value.
1507 current_xattr->value_length = xattr_value_len;
1508 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1511 * Protect ourself against things getting out of hand.
1513 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1514 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1515 jcr->last_fname, MAX_XATTR_STREAM);
1521 xattr_value_list->append(current_xattr);
1522 current_xattr = NULL;
1528 * Drop the local copy of the current_attrnamespace.
1530 actuallyfree(current_attrnamespace);
1531 current_attrnamespace = NULL;
1534 * We are done with this xattr list.
1537 xattr_list = (char *)NULL;
1541 * If we found any xattr send them to the SD.
1543 if (xattr_count > 0) {
1545 * Serialize the datastream.
1547 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1548 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1550 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1555 xattr_drop_internal_table(xattr_value_list);
1558 * Send the datastream to the SD.
1560 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
1562 xattr_drop_internal_table(xattr_value_list);
1564 return bxattr_exit_ok;
1568 if (current_attrnamespace != NULL) {
1569 actuallyfree(current_attrnamespace);
1571 if (current_xattr != NULL) {
1572 if (current_xattr->value != NULL) {
1573 free(current_xattr->value);
1575 if (current_xattr->name != NULL) {
1576 free(current_xattr->name);
1578 free(current_xattr);
1580 if (xattr_list != NULL) {
1583 if (xattr_value_list != NULL) {
1584 xattr_drop_internal_table(xattr_value_list);
1589 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
1591 xattr_t *current_xattr;
1592 alist *xattr_value_list;
1593 int current_attrnamespace, cnt;
1594 char *attrnamespace, *attrname;
1597 xattr_value_list = New(alist(10, not_owned_by_alist));
1599 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1600 xattr_drop_internal_table(xattr_value_list);
1601 return bxattr_exit_error;
1604 foreach_alist(current_xattr, xattr_value_list) {
1606 * Try splitting the xattr_name into a namespace and name part.
1607 * The splitting character is a .
1609 attrnamespace = current_xattr->name;
1610 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1611 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1612 current_xattr->name, jcr->last_fname);
1613 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1614 current_xattr->name, jcr->last_fname);
1620 * Make sure the attrnamespace makes sense.
1622 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1623 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1624 attrnamespace, jcr->last_fname);
1625 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1626 attrnamespace, jcr->last_fname);
1631 * Try restoring the extended attribute.
1633 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1634 attrname, current_xattr->value, current_xattr->value_length);
1635 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1641 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1642 jcr->last_fname, be.bstrerror());
1643 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1644 jcr->last_fname, be.bstrerror());
1651 xattr_drop_internal_table(xattr_value_list);
1652 return bxattr_exit_ok;
1655 xattr_drop_internal_table(xattr_value_list);
1656 return bxattr_exit_error;
1660 * Function pointers to the build and parse function to use for these xattrs.
1662 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1663 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1665 #elif defined(HAVE_OSF1_OS)
1667 #if !defined(HAVE_GETPROPLIST) || \
1668 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1669 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1670 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1671 !defined(HAVE_SETPROPLIST)
1672 #error "Missing full support for the Extended Attributes functions."
1675 #ifdef HAVE_SYS_PROPLIST_H
1676 #include <sys/proplist.h>
1678 #error "Missing sys/proplist.h header file"
1682 * Define the supported XATTR streams for this OS
1684 static int os_default_xattr_streams[1] = { STREAM_XATTR_TRU64 };
1685 static const char *xattr_acl_skiplist[1] = { NULL };
1686 static const char *xattr_skiplist[1] = { NULL };
1688 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1694 int xattr_count = 0;
1697 int32_t xattr_list_len,
1700 uint32_t expected_serialize_len = 0;
1701 xattr_t *current_xattr = NULL;
1702 alist *xattr_value_list = NULL;
1703 struct proplistname_args prop_args;
1704 bxattr_exit_code retval = bxattr_exit_error;
1705 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1708 xattrbuf_size = sizeof_pool_memory(xattrbuf);
1709 xattrbuf_min_size = 0;
1710 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1711 xattrbuf, &xattrbuf_min_size);
1714 * See what xattr are available.
1716 switch (xattr_list_len) {
1720 retval = bacl_exit_ok;
1723 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1724 jcr->last_fname, be.bstrerror());
1725 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1726 jcr->last_fname, be.bstrerror());
1731 if (xattrbuf_min_size) {
1733 * The buffer isn't big enough to hold the xattr data, we now have
1734 * a minimum buffersize so we resize the buffer and try again.
1736 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1737 xattrbuf_size = xattrbuf_min_size + 1;
1738 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1739 xattrbuf, &xattrbuf_min_size);
1740 switch (xattr_list_len) {
1744 retval = bacl_exit_ok;
1747 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1748 jcr->last_fname, be.bstrerror());
1749 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1750 jcr->last_fname, be.bstrerror());
1756 * This should never happen as we sized the buffer according to the minimumsize
1757 * returned by a previous getproplist call. If it does happen things are fishy and
1758 * we are better of forgetting this xattr as it seems its list is changing at this
1759 * exact moment so we can never make a good backup copy of it.
1761 retval = bacl_exit_ok;
1770 retval = bacl_exit_ok;
1778 xattr_value_list = New(alist(10, not_owned_by_alist));
1781 * Walk the list of extended attributes names and retrieve the data.
1782 * We already count the bytes needed for serializing the stream later on.
1785 while (xattrbuf_size > 0) {
1787 * Call getproplist_entry to initialize name and value
1788 * pointers to entries position within buffer.
1790 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
1793 * On some OSes you also get the acls in the extented attribute list.
1794 * So we check if we are already backing up acls and if we do we
1795 * don't store the extended attribute with the same info.
1797 if (ff_pkt->flags & FO_ACL) {
1798 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1799 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
1807 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1810 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1811 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
1819 Dmsg1(100, "Skipping xattr named %s\n", current_xattr->name);
1824 * Each xattr valuepair starts with a magic so we can parse it easier.
1826 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1827 current_xattr->magic = XATTR_MAGIC;
1828 expected_serialize_len += sizeof(current_xattr->magic);
1830 current_xattr->name_length = strlen(xattr_name);
1831 current_xattr->name = bstrdup(xattr_name);
1833 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1835 current_xattr->value_length = *xattr_value_len;
1836 current_xattr->value = (char *)malloc(current_xattr->value_length);
1837 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
1839 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1842 * Protect ourself against things getting out of hand.
1844 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1845 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1846 jcr->last_fname, MAX_XATTR_STREAM);
1850 xattr_value_list->append(current_xattr);
1851 current_xattr = NULL;
1856 * If we found any xattr send them to the SD.
1858 if (xattr_count > 0) {
1860 * Serialize the datastream.
1862 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1863 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1865 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1871 * Send the datastream to the SD.
1873 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1877 if (current_xattr != NULL) {
1878 if (current_xattr->value != NULL) {
1879 free(current_xattr->value);
1881 if (current_xattr->name != NULL) {
1882 free(current_xattr->name);
1884 free(current_xattr);
1886 if (xattr_value_list != NULL) {
1887 xattr_drop_internal_table(xattr_value_list);
1889 free_pool_memory(xattrbuf);
1894 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr, int stream)
1896 char *bp, *xattrbuf = NULL;
1897 int32_t xattrbuf_size, cnt;
1898 xattr_t *current_xattr;
1899 alist *xattr_value_list;
1902 xattr_value_list = New(alist(10, not_owned_by_alist));
1904 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1905 xattr_drop_internal_table(xattr_value_list);
1906 return bxattr_exit_error;
1910 * See how big the propertylist must be.
1913 foreach_alist(current_xattr, xattr_value_list) {
1914 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
1917 xattrbuf = (char *)malloc(xattrbuf_size);
1920 * Add all value pairs to the proplist.
1924 foreach_alist(current_xattr, xattr_value_list) {
1925 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
1926 current_xattr->value, &bp);
1932 if (cnt != xattrbuf_size) {
1933 Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
1935 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
1941 * Restore the list of extended attributes on the file.
1943 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
1948 retval = bacl_exit_ok;
1951 Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
1952 jcr->last_fname, be.bstrerror());
1953 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
1954 jcr->last_fname, be.bstrerror());
1964 xattr_drop_internal_table(xattr_value_list);
1965 return bxattr_exit_ok;
1971 xattr_drop_internal_table(xattr_value_list);
1972 return bxattr_exit_error;
1976 * Function pointers to the build and parse function to use for these xattrs.
1978 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_xattr_streams;
1979 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = tru64_parse_xattr_streams;
1981 #elif defined(HAVE_SUN_OS)
1983 * Solaris extended attributes were introduced in Solaris 9
1986 * Solaris extensible attributes were introduced in OpenSolaris
1987 * by PSARC 2007/315 Solaris extensible attributes are also
1988 * sometimes called extended system attributes.
1990 * man fsattr(5) on Solaris gives a wealth of info. The most
1991 * important bits are:
1993 * Attributes are logically supported as files within the file
1994 * system. The file system is therefore augmented with an
1995 * orthogonal name space of file attributes. Any file (includ-
1996 * ing attribute files) can have an arbitrarily deep attribute
1997 * tree associated with it. Attribute values are accessed by
1998 * file descriptors obtained through a special attribute inter-
1999 * face. This logical view of "attributes as files" allows the
2000 * leveraging of existing file system interface functionality
2001 * to support the construction, deletion, and manipulation of
2004 * The special files "." and ".." retain their accustomed
2005 * semantics within the attribute hierarchy. The "." attribute
2006 * file refers to the current directory and the ".." attribute
2007 * file refers to the parent directory. The unnamed directory
2008 * at the head of each attribute tree is considered the "child"
2009 * of the file it is associated with and the ".." file refers
2010 * to the associated file. For any non-directory file with
2011 * attributes, the ".." entry in the unnamed directory refers
2012 * to a file that is not a directory.
2014 * Conceptually, the attribute model is fully general. Extended
2015 * attributes can be any type of file (doors, links, direc-
2016 * tories, and so forth) and can even have their own attributes
2017 * (fully recursive). As a result, the attributes associated
2018 * with a file could be an arbitrarily deep directory hierarchy
2019 * where each attribute could have an equally complex attribute
2020 * tree associated with it. Not all implementations are able
2021 * to, or want to, support the full model. Implementation are
2022 * therefore permitted to reject operations that are not sup-
2023 * ported. For example, the implementation for the UFS file
2024 * system allows only regular files as attributes (for example,
2025 * no sub-directories) and rejects attempts to place attributes
2028 * The following list details the operations that are rejected
2029 * in the current implementation:
2031 * link Any attempt to create links between
2032 * attribute and non-attribute space
2033 * is rejected to prevent security-
2034 * related or otherwise sensitive
2035 * attributes from being exposed, and
2036 * therefore manipulable, as regular
2039 * rename Any attempt to rename between
2040 * attribute and non-attribute space
2041 * is rejected to prevent an already
2042 * linked file from being renamed and
2043 * thereby circumventing the link res-
2046 * mkdir, symlink, mknod Any attempt to create a "non-
2047 * regular" file in attribute space is
2048 * rejected to reduce the functional-
2049 * ity, and therefore exposure and
2050 * risk, of the initial implementa-
2053 * The entire available name space has been allocated to "gen-
2054 * eral use" to bring the implementation in line with the NFSv4
2055 * draft standard [NFSv4]. That standard defines "named attri-
2056 * butes" (equivalent to Solaris Extended Attributes) with no
2057 * naming restrictions. All Sun applications making use of
2058 * opaque extended attributes will use the prefix "SUNW".
2061 #ifdef HAVE_SYS_ATTR_H
2062 #include <sys/attr.h>
2069 #ifdef HAVE_SYS_NVPAIR_H
2070 #include <sys/nvpair.h>
2073 #ifdef HAVE_SYS_ACL_H
2074 #include <sys/acl.h>
2077 #if !defined(HAVE_OPENAT) || \
2078 !defined(HAVE_UNLINKAT) || \
2079 !defined(HAVE_FCHOWNAT) || \
2080 !defined(HAVE_FUTIMESAT)
2081 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2085 * Define the supported XATTR streams for this OS
2087 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2088 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
2090 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
2091 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2094 * This code creates a temporary cache with entries for each xattr which has
2095 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2097 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2099 xattr_link_cache_entry_t *ptr;
2101 foreach_alist(ptr, jcr->xattr_data->link_cache) {
2102 if (ptr && ptr->inum == inum) {
2109 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2111 xattr_link_cache_entry_t *ptr;
2113 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2114 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
2116 bstrncpy(ptr->target, target, sizeof(ptr->target));
2117 jcr->xattr_data->link_cache->append(ptr);
2120 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2122 * This function returns true if a non default extended system attribute
2123 * list is associated with fd and returns false when an error has occured
2124 * or when only extended system attributes other than archive,
2125 * av_modified or crtime are set.
2127 * The function returns true for the following cases:
2129 * - any extended system attribute other than the default attributes
2130 * ('archive', 'av_modified' and 'crtime') is set
2131 * - nvlist has NULL name string
2132 * - nvpair has data type of 'nvlist'
2133 * - default data type.
2135 static bool solaris_has_non_transient_extensible_attributes(int fd)
2143 bool retval = false;
2145 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2150 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2151 name = nvpair_name(pair);
2154 fattr = name_to_attr(name);
2160 type = nvpair_type(pair);
2162 case DATA_TYPE_BOOLEAN_VALUE:
2163 if (nvpair_value_boolean_value(pair, &value) != 0) {
2166 if (value && fattr != F_ARCHIVE &&
2167 fattr != F_AV_MODIFIED) {
2172 case DATA_TYPE_UINT64_ARRAY:
2173 if (fattr != F_CRTIME) {
2178 case DATA_TYPE_NVLIST:
2186 if (response != NULL) {
2187 nvlist_free(response);
2191 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2193 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2195 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2196 * There is no need to store those acls as we already store the stat bits too.
2198 static bool acl_is_trivial(int count, aclent_t *entries)
2203 for (n = 0; n < count; n++) {
2205 if (!(ace->a_type == USER_OBJ ||
2206 ace->a_type == GROUP_OBJ ||
2207 ace->a_type == OTHER_OBJ ||
2208 ace->a_type == CLASS_OBJ))
2213 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2215 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2218 #ifdef HAVE_EXTENDED_ACL
2224 * See if this attribute has an ACL
2226 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2227 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2229 * See if there is a non trivial acl on the file.
2231 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2232 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2235 return bxattr_exit_ok;
2237 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2238 attrname, jcr->last_fname, be.bstrerror());
2239 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2240 attrname, jcr->last_fname, be.bstrerror());
2241 return bxattr_exit_error;
2246 #if defined(ACL_SID_FMT)
2248 * New format flag added in newer Solaris versions.
2250 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2252 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2253 #endif /* ACL_SID_FMT */
2255 *acl_text = acl_totext(aclp, flags);
2263 return bxattr_exit_ok;
2264 #else /* HAVE_EXTENDED_ACL */
2266 aclent_t *acls = NULL;
2270 * See if this attribute has an ACL
2273 n = facl(fd, GETACLCNT, 0, NULL);
2275 n = acl(attrname, GETACLCNT, 0, NULL);
2278 if (n >= MIN_ACL_ENTRIES) {
2279 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2280 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2281 acl(attrname, GETACL, n, acls) != n) {
2285 return bxattr_exit_ok;
2287 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2288 attrname, jcr->last_fname, be.bstrerror());
2289 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2290 attrname, jcr->last_fname, be.bstrerror());
2292 return bxattr_exit_error;
2297 * See if there is a non trivial acl on the file.
2299 if (!acl_is_trivial(n, acls)) {
2300 if ((*acl_text = acltotext(acls, n)) == NULL) {
2301 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2302 attrname, jcr->last_fname, be.bstrerror());
2303 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2304 attrname, jcr->last_fname, be.bstrerror());
2306 return bxattr_exit_error;
2316 return bxattr_exit_ok;
2317 #endif /* HAVE_EXTENDED_ACL */
2319 #else /* HAVE_ACL */
2320 return bxattr_exit_ok;
2321 #endif /* HAVE_ACL */
2325 * Forward declaration for recursive function call.
2327 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2330 * Save an extended or extensible attribute.
2331 * This is stored as an opaque stream of bytes with the following encoding:
2333 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2335 * or for a hardlinked or symlinked attribute
2337 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2339 * xattr_name can be a subpath relative to the file the xattr is on.
2340 * stat_buffer is the string representation of the stat struct.
2341 * acl_string is an acl text when a non trivial acl is set on the xattr.
2342 * actual_xattr_data is the content of the xattr file.
2344 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2345 const char *attrname, bool toplevel_hidden_dir, int stream)
2350 xattr_link_cache_entry_t *xlce;
2351 char target_attrname[PATH_MAX];
2352 char link_source[PATH_MAX];
2353 char *acl_text = NULL;
2354 char attribs[MAXSTRING];
2355 char buffer[XATTR_BUFSIZ];
2356 bxattr_exit_code retval = bxattr_exit_error;
2359 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2362 * Get the stats of the extended or extensible attribute.
2364 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2367 retval = bxattr_exit_ok;
2370 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2371 target_attrname, jcr->last_fname, be.bstrerror());
2372 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2373 target_attrname, jcr->last_fname, be.bstrerror());
2379 * Based on the filetype perform the correct action. We support most filetypes here, more
2380 * then the actual implementation on Solaris supports so some code may never get executed
2381 * due to limitations in the implementation.
2383 switch (st.st_mode & S_IFMT) {
2388 * Get any acl on the xattr.
2390 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2394 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2395 * Encode the stat struct into an ASCII representation.
2397 encode_stat(attribs, &st, 0, stream);
2398 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2399 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2403 * Get any acl on the xattr.
2405 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2409 * See if this is the toplevel_hidden_dir being saved.
2411 if (toplevel_hidden_dir) {
2413 * Save the data for later storage when we encounter a real xattr. We store the data
2414 * in the jcr->xattr_data->content buffer and flush that just before sending out the
2415 * first real xattr. Encode the stat struct into an ASCII representation and jump
2416 * out of the function.
2418 encode_stat(attribs, &st, 0, stream);
2419 cnt = bsnprintf(buffer, sizeof(buffer),
2421 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2422 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2423 jcr->xattr_data->content_length = cnt;
2427 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2428 * Encode the stat struct into an ASCII representation.
2430 encode_stat(attribs, &st, 0, stream);
2431 cnt = bsnprintf(buffer, sizeof(buffer),
2433 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2438 * If this is a hardlinked file check the inode cache for a hit.
2440 if (st.st_nlink > 1) {
2442 * See if the cache already knows this inode number.
2444 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2446 * Generate a xattr encoding with the reference to the target in there.
2448 encode_stat(attribs, &st, st.st_ino, stream);
2449 cnt = bsnprintf(buffer, sizeof(buffer),
2451 target_attrname, 0, attribs, 0, xlce->target, 0);
2452 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2453 jcr->xattr_data->content_length = cnt;
2454 retval = send_xattr_stream(jcr, stream);
2457 * For a hard linked file we are ready now, no need to recursively save the attributes.
2463 * Store this hard linked file in the cache.
2464 * Store the name relative to the top level xattr space.
2466 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2470 * Get any acl on the xattr.
2472 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2477 * Encode the stat struct into an ASCII representation.
2479 encode_stat(attribs, &st, 0, stream);
2480 cnt = bsnprintf(buffer, sizeof(buffer),
2482 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2485 * Open the extended or extensible attribute file.
2487 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2490 retval = bxattr_exit_ok;
2493 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2494 target_attrname, jcr->last_fname, be.bstrerror());
2495 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2496 target_attrname, jcr->last_fname, be.bstrerror());
2503 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2504 * Encode the stat struct into an ASCII representation.
2506 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2509 retval = bxattr_exit_ok;
2512 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2513 target_attrname, jcr->last_fname, be.bstrerror());
2514 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2515 target_attrname, jcr->last_fname, be.bstrerror());
2521 * Generate a xattr encoding with the reference to the target in there.
2523 encode_stat(attribs, &st, st.st_ino, stream);
2524 cnt = bsnprintf(buffer, sizeof(buffer),
2526 target_attrname, 0, attribs, 0, link_source, 0);
2527 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2528 jcr->xattr_data->content_length = cnt;
2529 retval = send_xattr_stream(jcr, stream);
2531 if (retval == bxattr_exit_ok) {
2532 jcr->xattr_data->nr_saved++;
2536 * For a soft linked file we are ready now, no need to recursively save the attributes.
2544 * See if this is the first real xattr being saved.
2545 * If it is save the toplevel_hidden_dir attributes first.
2546 * This is easy as its stored already in the jcr->xattr_data->content buffer.
2548 if (jcr->xattr_data->nr_saved == 0) {
2549 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2550 if (retval != bxattr_exit_ok) {
2553 jcr->xattr_data->nr_saved++;
2556 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2557 jcr->xattr_data->content_length = cnt;
2560 * Only dump the content of regular files.
2562 switch (st.st_mode & S_IFMT) {
2564 if (st.st_size > 0) {
2566 * Protect ourself against things getting out of hand.
2568 if (st.st_size >= MAX_XATTR_STREAM) {
2569 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2570 jcr->last_fname, MAX_XATTR_STREAM);
2574 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2575 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
2576 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
2577 jcr->xattr_data->content_length += cnt;
2581 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
2582 target_attrname, jcr->last_fname);
2583 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2584 target_attrname, jcr->last_fname);
2595 retval = send_xattr_stream(jcr, stream);
2596 if (retval == bxattr_exit_ok) {
2597 jcr->xattr_data->nr_saved++;
2602 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2603 * available on this extended attribute.
2606 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2609 * The recursive call could change our working dir so change back to the wanted workdir.
2611 if (fchdir(fd) < 0) {
2614 retval = bxattr_exit_ok;
2617 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2618 jcr->last_fname, be.bstrerror());
2619 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2620 jcr->last_fname, fd, be.bstrerror());
2627 if (acl_text != NULL) {
2636 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2639 int fd, filefd = -1, attrdirfd = -1;
2642 char current_xattr_namespace[PATH_MAX];
2643 bxattr_exit_code retval = bxattr_exit_error;
2647 * Determine what argument to use. Use attr_parent when set
2648 * (recursive call) or jcr->last_fname for first call. Also save
2649 * the current depth of the xattr_space we are in.
2653 if (xattr_namespace) {
2654 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2655 xattr_namespace, attr_parent);
2657 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2660 name = jcr->last_fname;
2661 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2665 * Open the file on which to save the xattrs read-only.
2667 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2670 retval = bxattr_exit_ok;
2673 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2674 jcr->last_fname, be.bstrerror());
2675 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2676 jcr->last_fname, be.bstrerror());
2682 * Open the xattr naming space.
2684 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2688 * Gentile way of the system saying this type of xattr layering is not supported.
2689 * Which is not problem we just forget about this this xattr.
2690 * But as this is not an error we return a positive return value.
2692 retval = bxattr_exit_ok;
2695 retval = bxattr_exit_ok;
2698 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2699 name, jcr->last_fname, be.bstrerror());
2700 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2701 name, jcr->last_fname, be.bstrerror());
2707 * We need to change into the attribute directory to determine if each of the
2708 * attributes should be saved.
2710 if (fchdir(attrdirfd) < 0) {
2711 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2712 jcr->last_fname, be.bstrerror());
2713 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2714 jcr->last_fname, attrdirfd, be.bstrerror());
2719 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2720 * else because the readdir returns "." entry after the extensible attr entry.
2721 * And as we want this entry before anything else we better just save its data.
2724 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2725 true, STREAM_XATTR_SOLARIS);
2727 if ((fd = dup(attrdirfd)) == -1 ||
2728 (dirp = fdopendir(fd)) == (DIR *)NULL) {
2729 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2730 jcr->last_fname, be.bstrerror());
2731 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
2732 jcr->last_fname, fd, be.bstrerror());
2738 * Walk the namespace.
2740 while ((dp = readdir(dirp)) != NULL) {
2742 * Skip only the toplevel . dir.
2744 if (!attr_parent && bstrcmp(dp->d_name, "."))
2748 * Skip all .. directories
2750 if (bstrcmp(dp->d_name, ".."))
2753 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2754 current_xattr_namespace, dp->d_name, jcr->last_fname);
2756 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2758 * We are not interested in read-only extensible attributes.
2760 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2761 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2762 current_xattr_namespace, dp->d_name, jcr->last_fname);
2768 * We are only interested in read-write extensible attributes
2769 * when they contain non-transient values.
2771 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2773 * Determine if there are non-transient system attributes at the toplevel.
2774 * We need to provide a fd to the open file.
2776 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2777 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2778 current_xattr_namespace, dp->d_name, jcr->last_fname);
2785 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2786 false, STREAM_XATTR_SOLARIS_SYS);
2789 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2794 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2795 false, STREAM_XATTR_SOLARIS);
2799 retval = bxattr_exit_ok;
2802 if (attrdirfd != -1)
2810 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
2812 #ifdef HAVE_EXTENDED_ACL
2817 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
2818 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
2820 return bxattr_exit_error;
2823 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
2824 acl_set(attrname, aclp) != 0) {
2825 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2826 attrname, jcr->last_fname, be.bstrerror());
2827 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2828 attrname, jcr->last_fname, be.bstrerror());
2829 return bxattr_exit_error;
2835 return bxattr_exit_ok;
2837 #else /* HAVE_EXTENDED_ACL */
2839 aclent_t *acls = NULL;
2842 acls = aclfromtext(acl_text, &n);
2844 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
2845 acl(attrname, SETACL, n, acls) != 0) {
2846 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2847 attrname, jcr->last_fname, be.bstrerror());
2848 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2849 attrname, jcr->last_fname, be.bstrerror());
2850 return bxattr_exit_error;
2857 return bxattr_exit_ok;
2859 #endif /* HAVE_EXTENDED_ACL */
2862 #endif /* HAVE_ACL */
2864 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
2866 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
2867 int used_bytes, total_bytes, cnt;
2868 char *bp, *target_attrname, *attribs;
2869 char *linked_target = NULL;
2870 char *acl_text = NULL;
2874 struct timeval times[2];
2875 bxattr_exit_code retval = bxattr_exit_error;
2879 * Parse the xattr stream. First the part that is the same for all xattrs.
2882 total_bytes = jcr->xattr_data->content_length;
2885 * The name of the target xattr has a leading / we are not interested
2886 * in that so skip it when decoding the string. We always start a the /
2887 * of the xattr space anyway.
2889 target_attrname = jcr->xattr_data->content + 1;
2890 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
2891 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2897 * Open the file on which to restore the xattrs read-only.
2899 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
2900 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2901 jcr->last_fname, be.bstrerror());
2902 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2903 jcr->last_fname, be.bstrerror());
2908 * Open the xattr naming space and make it the current working dir.
2910 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2911 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
2912 jcr->last_fname, be.bstrerror());
2913 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
2914 jcr->last_fname, be.bstrerror());
2918 if (fchdir(attrdirfd) < 0) {
2919 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2920 jcr->last_fname, be.bstrerror());
2921 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2922 jcr->last_fname, attrdirfd, be.bstrerror());
2927 * Try to open the correct xattr subdir based on the target_attrname given.
2928 * e.g. check if its a subdir attrname. Each / in the string makes us go
2931 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2934 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2935 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2936 target_attrname, jcr->last_fname, be.bstrerror());
2937 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2938 target_attrname, jcr->last_fname, be.bstrerror());
2946 * Open the xattr naming space.
2948 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2949 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2950 target_attrname, jcr->last_fname, be.bstrerror());
2951 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2952 target_attrname, jcr->last_fname, be.bstrerror());
2960 * Make the xattr space our current workingdir.
2962 if (fchdir(attrdirfd) < 0) {
2963 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2964 target_attrname, jcr->last_fname, be.bstrerror());
2965 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2966 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2970 target_attrname = ++bp;
2974 * Decode the attributes from the stream.
2976 decode_stat(attribs, &st, &inum);
2979 * Decode the next field (acl_text).
2981 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2982 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2988 * Based on the filetype perform the correct action. We support most filetypes here, more
2989 * then the actual implementation on Solaris supports so some code may never get executed
2990 * due to limitations in the implementation.
2992 switch (st.st_mode & S_IFMT) {
2995 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2997 unlinkat(attrdirfd, target_attrname, 0);
2998 if (mkfifo(target_attrname, st.st_mode) < 0) {
2999 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3000 target_attrname, jcr->last_fname, be.bstrerror());
3001 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
3002 target_attrname, jcr->last_fname, be.bstrerror());
3009 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3011 unlinkat(attrdirfd, target_attrname, 0);
3012 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3013 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3014 target_attrname, jcr->last_fname, be.bstrerror());
3015 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3016 target_attrname, jcr->last_fname, be.bstrerror());
3022 * If its not the hidden_dir create the entry.
3023 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3025 if (!bstrcmp(target_attrname, ".")) {
3026 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3027 if (mkdir(target_attrname, st.st_mode) < 0) {
3028 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3029 target_attrname, jcr->last_fname, be.bstrerror());
3030 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3031 target_attrname, jcr->last_fname, be.bstrerror());
3038 * See if this is a hard linked file. e.g. inum != 0
3043 unlinkat(attrdirfd, target_attrname, 0);
3044 if (link(linked_target, target_attrname) < 0) {
3045 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3046 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3047 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3048 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3053 * Successfully restored xattr.
3055 retval = bxattr_exit_ok;
3058 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3059 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
3063 if (used_bytes < (total_bytes - 1))
3067 * Restore the actual xattr.
3069 if (!is_extensible) {
3070 unlinkat(attrdirfd, target_attrname, 0);
3073 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3074 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3075 target_attrname, jcr->last_fname, be.bstrerror());
3076 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3077 target_attrname, jcr->last_fname, be.bstrerror());
3083 * Restore the actual data.
3085 if (st.st_size > 0) {
3086 used_bytes = (data - jcr->xattr_data->content);
3087 cnt = total_bytes - used_bytes;
3090 * Do a sanity check, the st.st_size should be the same as the number of bytes
3091 * we have available as data of the stream.
3093 if (cnt != st.st_size) {
3094 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3095 target_attrname, jcr->last_fname);
3096 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3097 target_attrname, jcr->last_fname);
3102 cnt = write(attrfd, data, cnt);
3104 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3105 target_attrname, jcr->last_fname, be.bstrerror());
3106 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3107 target_attrname, jcr->last_fname, be.bstrerror());
3113 cnt = total_bytes - used_bytes;
3119 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3123 if (symlink(linked_target, target_attrname) < 0) {
3124 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3125 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3126 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3127 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3132 * Successfully restored xattr.
3134 retval = bxattr_exit_ok;
3141 * Restore owner and acl for non extensible attributes.
3143 if (!is_extensible) {
3144 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3148 * Gentile way of the system saying this type of xattr layering is not supported.
3149 * But as this is not an error we return a positive return value.
3151 retval = bxattr_exit_ok;
3154 retval = bxattr_exit_ok;
3157 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3158 target_attrname, jcr->last_fname, be.bstrerror());
3159 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3160 target_attrname, jcr->last_fname, be.bstrerror());
3167 if (acl_text && *acl_text)
3168 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3170 #endif /* HAVE_ACL */
3173 * For a non extensible attribute restore access and modification time on the xattr.
3175 if (!is_extensible) {
3176 times[0].tv_sec = st.st_atime;
3177 times[0].tv_usec = 0;
3178 times[1].tv_sec = st.st_mtime;
3179 times[1].tv_usec = 0;
3181 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3182 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3183 target_attrname, jcr->last_fname, be.bstrerror());
3184 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3185 target_attrname, jcr->last_fname, be.bstrerror());
3191 * Successfully restored xattr.
3193 retval = bxattr_exit_ok;
3197 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3199 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3206 if (attrdirfd != -1) {
3215 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3218 bxattr_exit_code retval = bxattr_exit_ok;
3221 * First see if extended attributes or extensible attributes are present.
3222 * If not just pretend things went ok.
3224 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3225 jcr->xattr_data->nr_saved = 0;
3226 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
3229 * As we change the cwd in the save function save the current cwd
3230 * for restore after return from the solaris_save_xattrs function.
3232 getcwd(cwd, sizeof(cwd));
3233 retval = solaris_save_xattrs(jcr, NULL, NULL);
3235 delete jcr->xattr_data->link_cache;
3236 jcr->xattr_data->link_cache = NULL;
3241 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
3244 bool is_extensible = false;
3245 bxattr_exit_code retval;
3248 * First make sure we can restore xattr on the filesystem.
3251 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3252 case STREAM_XATTR_SOLARIS_SYS:
3253 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3254 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
3255 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3257 return bxattr_exit_error;
3260 is_extensible = true;
3263 case STREAM_XATTR_SOLARIS:
3264 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3265 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
3266 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3268 return bxattr_exit_error;
3272 return bxattr_exit_error;
3276 * As we change the cwd in the restore function save the current cwd
3277 * for restore after return from the solaris_restore_xattrs function.
3279 getcwd(cwd, sizeof(cwd));
3280 retval = solaris_restore_xattrs(jcr, is_extensible);
3287 * Function pointers to the build and parse function to use for these xattrs.
3289 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
3290 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
3292 #endif /* defined(HAVE_SUN_OS) */
3295 * Entry points when compiled with support for XATTRs on a supported platform.
3297 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3299 if (os_build_xattr_streams) {
3300 return (*os_build_xattr_streams)(jcr, ff_pkt);
3302 return bxattr_exit_error;
3305 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
3309 if (os_parse_xattr_streams) {
3311 * See if we can parse this stream, and ifso give it a try.
3313 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3314 if (os_default_xattr_streams[cnt] == stream) {
3315 return (*os_parse_xattr_streams)(jcr, stream);
3320 * Issue a warning and discard the message. But pretend the restore was ok.
3322 Jmsg2(jcr, M_WARNING, 0,
3323 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3324 jcr->last_fname, stream);
3325 return bxattr_exit_error;