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
56 #if !defined(HAVE_XATTR)
58 * Entry points when compiled without support for XATTRs or on an unsupported platform.
60 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
62 return bxattr_exit_fatal;
65 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
67 return bxattr_exit_fatal;
71 * Send a XATTR stream to the SD.
73 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
75 BSOCK *sd = jcr->store_bsock;
77 #ifdef FD_NO_SEND_TEST
78 return bxattr_exit_ok;
84 if (jcr->xattr_data->content_length <= 0) {
85 return bxattr_exit_ok;
91 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
92 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
94 return bxattr_exit_fatal;
98 * Send the buffer to the storage deamon
100 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
102 sd->msg = jcr->xattr_data->content;
103 sd->msglen = jcr->xattr_data->content_length;
107 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
109 return bxattr_exit_fatal;
112 jcr->JobBytes += sd->msglen;
114 if (!sd->signal(BNET_EOD)) {
115 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
117 return bxattr_exit_fatal;
119 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
120 return bxattr_exit_ok;
124 * First some generic functions for OSes that use the same xattr encoding scheme.
125 * Currently for all OSes except for Solaris.
127 #if !defined(HAVE_SUN_OS)
128 static void xattr_drop_internal_table(alist *xattr_value_list)
130 xattr_t *current_xattr;
133 * Walk the list of xattrs and free allocated memory on traversing.
135 foreach_alist(current_xattr, xattr_value_list) {
137 * See if we can shortcut.
139 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
142 free(current_xattr->name);
144 if (current_xattr->value_length > 0)
145 free(current_xattr->value);
150 delete xattr_value_list;
154 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
155 * which encodes one or more xattr_t structures.
157 * The Serialized stream consists of the following elements:
158 * magic - A magic string which makes it easy to detect any binary incompatabilites
159 * name_length - The length of the following xattr name
160 * name - The name of the extended attribute
161 * value_length - The length of the following xattr data
162 * value - The actual content of the extended attribute
164 * This is repeated 1 or more times.
167 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, alist *xattr_value_list)
169 xattr_t *current_xattr;
173 * Make sure the serialized stream fits in the poolmem buffer.
174 * We allocate some more to be sure the stream is gonna fit.
176 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
177 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
180 * Walk the list of xattrs and serialize the data.
182 foreach_alist(current_xattr, xattr_value_list) {
184 * See if we can shortcut.
186 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
189 ser_uint32(current_xattr->magic);
190 ser_uint32(current_xattr->name_length);
191 ser_bytes(current_xattr->name, current_xattr->name_length);
193 ser_uint32(current_xattr->value_length);
194 if (current_xattr->value_length > 0 && current_xattr->value) {
195 ser_bytes(current_xattr->value, current_xattr->value_length);
197 Dmsg3(100, "Backup xattr named %s, value %*s\n",
198 current_xattr->name, current_xattr->value, current_xattr->value);
200 Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
204 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
205 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
207 return jcr->xattr_data->content_length;
210 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
213 xattr_t *current_xattr;
214 bxattr_exit_code retval = bxattr_exit_ok;
217 * Parse the stream and call restore_xattr_on_file for each extended attribute.
219 * Start unserializing the data. We keep on looping while we have not
220 * unserialized all bytes in the stream.
222 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
223 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
225 * First make sure the magic is present. This way we can easily catch corruption.
226 * Any missing MAGIC is fatal we do NOT try to continue.
228 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
229 unser_uint32(current_xattr->magic);
230 if (current_xattr->magic != XATTR_MAGIC) {
231 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
233 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
236 return bxattr_exit_error;
240 * Decode the valuepair. First decode the length of the name.
242 unser_uint32(current_xattr->name_length);
243 if (current_xattr->name_length == 0) {
244 Mmsg1(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
246 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
249 return bxattr_exit_error;
253 * Allocate room for the name and decode its content.
255 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
256 unser_bytes(current_xattr->name, current_xattr->name_length);
259 * The xattr_name needs to be null terminated.
261 current_xattr->name[current_xattr->name_length] = '\0';
264 * Decode the value length.
266 unser_uint32(current_xattr->value_length);
268 if (current_xattr->value_length > 0) {
270 * Allocate room for the value and decode its content.
272 current_xattr->value = (char *)malloc(current_xattr->value_length);
273 unser_bytes(current_xattr->value, current_xattr->value_length);
275 Dmsg3(100, "Restoring xattr named %s, value %*s\n",
276 current_xattr->name, current_xattr->value, current_xattr->value);
278 current_xattr->value = NULL;
279 Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
282 xattr_value_list->append(current_xattr);
285 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
291 * This is a supported OS, See what kind of interface we should use.
293 #if defined(HAVE_AIX_OS)
295 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
296 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
297 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
298 #error "Missing full support for the Extended Attributes (EA) functions."
304 #error "Missing sys/ea.h header file"
308 * Define the supported XATTR streams for this OS
310 static int os_default_xattr_streams[1] = { STREAM_XATTR_AIX };
313 * Fallback to the non l-functions when those are not available.
315 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
318 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
321 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
322 #define llistea listea
325 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
328 char *xattr_list, *bp;
329 int cnt, xattr_count = 0;
330 uint32_t name_length;
331 int32_t xattr_list_len,
333 uint32_t expected_serialize_len = 0;
334 xattr_t *current_xattr = NULL;
335 alist *xattr_value_list = NULL;
336 bxattr_exit_code retval = bxattr_exit_error;
340 * First get the length of the available list with extended attributes.
342 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
343 switch (xattr_list_len) {
349 return bxattr_exit_ok;
351 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
352 jcr->last_fname, be.bstrerror());
353 Dmsg2(100, "llistea error file=%s ERR=%s\n",
354 jcr->last_fname, be.bstrerror());
355 return bxattr_exit_error;
359 return bxattr_exit_ok;
365 * Allocate room for the extented attribute list.
367 xattr_list = (char *)malloc(xattr_list_len + 1);
368 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
371 * Get the actual list of extended attributes names for a file.
373 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
374 switch (xattr_list_len) {
380 retval = bxattr_exit_ok;
383 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
384 jcr->last_fname, be.bstrerror());
385 Dmsg2(100, "llistea error file=%s ERR=%s\n",
386 jcr->last_fname, be.bstrerror());
393 xattr_list[xattr_list_len] = '\0';
396 * Walk the list of extended attributes names and retrieve the data.
397 * We already count the bytes needed for serializing the stream later on.
400 while ((bp - xattr_list) + 1 < xattr_list_len) {
404 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
410 name_length = strlen(bp);
411 if (skip_xattr || name_length == 0) {
412 Dmsg1(100, "Skipping xattr named %s\n", bp);
413 bp = strchr(bp, '\0') + 1;
418 * Each xattr valuepair starts with a magic so we can parse it easier.
420 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
421 current_xattr->magic = XATTR_MAGIC;
422 expected_serialize_len += sizeof(current_xattr->magic);
425 * Allocate space for storing the name.
427 current_xattr->name_length = name_length;
428 current_xattr->name = (char *)malloc(current_xattr->name_length);
429 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
431 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
434 * First see how long the value is for the extended attribute.
436 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
437 switch (xattr_value_len) {
443 retval = bxattr_exit_ok;
446 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
447 jcr->last_fname, be.bstrerror());
448 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
449 jcr->last_fname, be.bstrerror());
454 current_xattr->value = NULL;
455 current_xattr->value_length = 0;
456 expected_serialize_len += sizeof(current_xattr->value_length);
460 * Allocate space for storing the value.
462 current_xattr->value = (char *)malloc(xattr_value_len);
463 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
465 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
466 if (xattr_value_len < 0) {
471 retval = bxattr_exit_ok;
474 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
475 jcr->last_fname, be.bstrerror());
476 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
477 jcr->last_fname, be.bstrerror());
482 * Store the actual length of the value.
484 current_xattr->value_length = xattr_value_len;
485 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
488 * Protect ourself against things getting out of hand.
490 if (expected_serialize_len >= MAX_XATTR_STREAM) {
491 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
492 jcr->last_fname, MAX_XATTR_STREAM);
497 if (xattr_value_list == NULL) {
498 xattr_value_list = New(alist(10, not_owned_by_alist));
501 xattr_value_list->append(current_xattr);
502 current_xattr = NULL;
504 bp = strchr(bp, '\0') + 1;
509 xattr_list = (char *)NULL;
512 * If we found any xattr send them to the SD.
514 if (xattr_count > 0) {
516 * Serialize the datastream.
518 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
519 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
521 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
527 * Send the datastream to the SD.
529 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
531 retval = bxattr_exit_ok;
535 if (current_xattr != NULL) {
536 if (current_xattr->value != NULL) {
537 free(current_xattr->value);
539 if (current_xattr->name != NULL) {
540 free(current_xattr->name);
544 if (xattr_list != NULL) {
547 if (xattr_value_list != NULL) {
548 xattr_drop_internal_table(xattr_value_list);
553 static bxattr_exit_code aix_xattr_parse_streams(JCR *jcr, int stream)
555 xattr_t *current_xattr;
556 alist *xattr_value_list;
559 xattr_value_list = New(alist(10, not_owned_by_alist));
561 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
562 xattr_drop_internal_table(xattr_value_list);
563 return bxattr_exit_error;
566 foreach_alist(current_xattr, xattr_value_list) {
567 if (lsetea(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
574 Mmsg2(jcr->errmsg, _("lsetea error on file \"%s\": ERR=%s\n"),
575 jcr->last_fname, be.bstrerror());
576 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
577 jcr->last_fname, be.bstrerror());
583 xattr_drop_internal_table(xattr_value_list);
584 return bxattr_exit_ok;
587 xattr_drop_internal_table(xattr_value_list);
588 return bxattr_exit_error;
592 * Function pointers to the build and parse function to use for these xattrs.
594 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_xattr_build_streams;
595 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = aix_xattr_parse_streams;
597 #elif defined(HAVE_IRIX_OS)
599 #include <sys/attributes.h>
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, length, 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 &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 &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());
713 current_xattr->value_length = length;
717 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
718 jcr->last_fname, be.bstrerror());
719 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
720 jcr->last_fname, be.bstrerror());
724 current_xattr->value_length = length;
727 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
730 * Protect ourself against things getting out of hand.
732 if (expected_serialize_len >= MAX_XATTR_STREAM) {
733 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
734 jcr->last_fname, MAX_XATTR_STREAM);
738 if (xattr_value_list == NULL) {
739 xattr_value_list = New(alist(10, not_owned_by_alist));
742 xattr_value_list->append(current_xattr);
743 current_xattr = NULL;
748 * See if there are more attributes available for a next run of attr_list.
750 if (attrlist->al_more == 0) {
757 * If we found any xattr send them to the SD.
759 if (xattr_count > 0) {
761 * Serialize the datastream.
763 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
764 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
766 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
772 * Send the datastream to the SD.
774 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
776 retval = bxattr_exit_ok;
780 if (current_xattr != NULL) {
781 if (current_xattr->value != NULL) {
782 free(current_xattr->value);
784 if (current_xattr->name != NULL) {
785 free(current_xattr->name);
789 free_pool_memory(xattrbuf);
791 if (xattr_value_list != NULL) {
792 xattr_drop_internal_table(xattr_value_list);
797 static bxattr_exit_code irix_xattr_parse_streams(JCR *jcr, int stream)
800 int cnt, cmp_size, name_space_index, flags;
801 xattr_t *current_xattr;
802 alist *xattr_value_list;
803 bxattr_exit_code retval = bxattr_exit_error;
806 xattr_value_list = New(alist(10, not_owned_by_alist));
808 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
809 xattr_drop_internal_table(xattr_value_list);
810 return bxattr_exit_error;
813 foreach_alist(current_xattr, xattr_value_list) {
815 * See to what namingspace this xattr belongs to.
817 name_space_index = 0;
818 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
819 cmp_size = strlen(xattr_naming_spaces[cnt].name);
820 if (!strncasecmp(current_xattr->name,
821 xattr_naming_spaces[cnt].name,
823 name_space_index = cnt;
829 * If we got a xattr that doesn't belong to an valid namespace complain.
831 if (name_space_index == 0) {
832 Mmsg2(jcr->errmsg, _("Received illegal xattr named %s on file \"%s\"\n"),
833 current_xattr->name, jcr->last_fname);
834 Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
835 current_xattr->name, jcr->last_fname);
840 * Restore the xattr first try to create the attribute from scratch.
842 flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
843 bp = strchr(current_xattr->name, '.');
844 if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
845 current_xattr->value_length, flags) != 0) {
848 retval = bxattr_exit_ok;
852 * The xattr already exists we need to replace it.
854 flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
855 if (attr_set(jcr->last_fname, bp, current_xattr->value,
856 current_xattr->value_length, flags) != 0) {
859 retval = bxattr_exit_ok;
862 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
863 jcr->last_fname, be.bstrerror());
864 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
865 jcr->last_fname, be.bstrerror());
871 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
872 jcr->last_fname, be.bstrerror());
873 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
874 jcr->last_fname, be.bstrerror());
880 xattr_drop_internal_table(xattr_value_list);
881 return bxattr_exit_ok;
884 xattr_drop_internal_table(xattr_value_list);
885 return bxattr_exit_error;
889 * Function pointers to the build and parse function to use for these xattrs.
891 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = irix_xattr_build_streams;
892 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = irix_xattr_parse_streams;
894 #elif defined(HAVE_DARWIN_OS) || \
895 defined(HAVE_LINUX_OS)
897 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
898 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
899 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
900 #error "Missing full support for the XATTR functions."
903 #ifdef HAVE_SYS_XATTR_H
904 #include <sys/xattr.h>
906 #error "Missing sys/xattr.h header file"
910 * Define the supported XATTR streams for this OS
912 #if defined(HAVE_DARWIN_OS)
913 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
914 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
915 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
916 #elif defined(HAVE_LINUX_OS)
917 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
918 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
919 static const char *xattr_skiplist[1] = { NULL };
923 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
924 * listxattr, getxattr and setxattr with an extra options argument
925 * which mimics the l variants of the functions when we specify
926 * XATTR_NOFOLLOW as the options value.
928 #if defined(HAVE_DARWIN_OS)
929 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
930 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
931 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
934 * Fallback to the non l-functions when those are not available.
936 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
937 #define lgetxattr getxattr
939 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
940 #define lsetxattr setxattr
942 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
943 #define llistxattr listxattr
947 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
950 char *xattr_list, *bp;
951 int cnt, xattr_count = 0;
952 uint32_t name_length;
953 int32_t xattr_list_len,
955 uint32_t expected_serialize_len = 0;
956 xattr_t *current_xattr = NULL;
957 alist *xattr_value_list = NULL;
958 bxattr_exit_code retval = bxattr_exit_error;
962 * First get the length of the available list with extended attributes.
964 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
965 switch (xattr_list_len) {
970 return bxattr_exit_ok;
972 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
973 jcr->last_fname, be.bstrerror());
974 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
975 jcr->last_fname, be.bstrerror());
976 return bxattr_exit_error;
980 return bxattr_exit_ok;
986 * Allocate room for the extented attribute list.
988 xattr_list = (char *)malloc(xattr_list_len + 1);
989 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
992 * Get the actual list of extended attributes names for a file.
994 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
995 switch (xattr_list_len) {
1000 retval = bxattr_exit_ok;
1003 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
1004 jcr->last_fname, be.bstrerror());
1005 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1006 jcr->last_fname, be.bstrerror());
1013 xattr_list[xattr_list_len] = '\0';
1016 * Walk the list of extended attributes names and retrieve the data.
1017 * We already count the bytes needed for serializing the stream later on.
1020 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_length = strlen(bp);
1050 if (skip_xattr || name_length == 0) {
1051 Dmsg1(100, "Skipping xattr named %s\n", bp);
1052 bp = strchr(bp, '\0') + 1;
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_length;
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 if (xattr_value_list == NULL) {
1135 xattr_value_list = New(alist(10, not_owned_by_alist));
1138 xattr_value_list->append(current_xattr);
1139 current_xattr = NULL;
1141 bp = strchr(bp, '\0') + 1;
1146 xattr_list = (char *)NULL;
1149 * If we found any xattr send them to the SD.
1151 if (xattr_count > 0) {
1153 * Serialize the datastream.
1155 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1156 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1158 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1164 * Send the datastream to the SD.
1166 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1168 retval = 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[4] = { "system.posix1e.acl_access", "system.posix1e.acl_default", "system.nfs4.acl", 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;
1300 * Loop over all available xattr namespaces.
1302 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
1303 attrnamespace = os_default_xattr_namespaces[namespace_index];
1306 * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
1307 * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
1309 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1310 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
1311 attrnamespace, jcr->last_fname);
1312 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1313 attrnamespace, jcr->last_fname);
1318 * First get the length of the available list with extended attributes.
1319 * If we get EPERM on system namespace, don't return error.
1320 * This is expected for normal users trying to archive the system
1321 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1322 * they've decided to return EOPNOTSUPP instead.
1324 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1325 switch (xattr_list_len) {
1329 retval = bxattr_exit_ok;
1331 #if defined(EOPNOTSUPP)
1335 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1336 actuallyfree(current_attrnamespace);
1337 current_attrnamespace = NULL;
1344 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1345 jcr->last_fname, be.bstrerror());
1346 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1347 jcr->last_fname, be.bstrerror());
1358 * Allocate room for the extented attribute list.
1360 xattr_list = (char *)malloc(xattr_list_len + 1);
1361 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
1364 * Get the actual list of extended attributes names for a file.
1366 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
1367 switch (xattr_list_len) {
1371 retval = bxattr_exit_ok;
1374 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1375 jcr->last_fname, be.bstrerror());
1376 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1377 jcr->last_fname, be.bstrerror());
1384 xattr_list[xattr_list_len] = '\0';
1387 * Walk the list of extended attributes names and retrieve the data.
1388 * We already count the bytes needed for serializing the stream later on.
1390 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1394 * Print the current name into the buffer as its not null terminated we need to
1395 * use the length encoded in the string for copying only the needed bytes.
1397 cnt = xattr_list[index];
1398 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1399 cnt = ((int)sizeof(current_attrname) - 1);
1401 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1402 current_attrname[cnt] = '\0';
1405 * First make a xattr tuple of the current namespace and the name of the xattr.
1406 * e.g. something like user.<attrname> or system.<attrname>
1408 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
1411 * On some OSes you also get the acls in the extented attribute list.
1412 * So we check if we are already backing up acls and if we do we
1413 * don't store the extended attribute with the same info.
1415 if (ff_pkt->flags & FO_ACL) {
1416 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1417 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1425 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1428 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1429 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1437 Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1442 * Each xattr valuepair starts with a magic so we can parse it easier.
1444 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1445 current_xattr->magic = XATTR_MAGIC;
1446 expected_serialize_len += sizeof(current_xattr->magic);
1449 * Allocate space for storing the name.
1451 current_xattr->name_length = strlen(current_attrtuple);
1452 current_xattr->name = (char *)malloc(current_xattr->name_length);
1453 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
1455 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1458 * First see how long the value is for the extended attribute.
1460 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
1461 switch (xattr_value_len) {
1465 retval = bxattr_exit_ok;
1468 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1469 jcr->last_fname, be.bstrerror());
1470 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1471 jcr->last_fname, be.bstrerror());
1476 current_xattr->value = NULL;
1477 current_xattr->value_length = 0;
1478 expected_serialize_len += sizeof(current_xattr->value_length);
1482 * Allocate space for storing the value.
1484 current_xattr->value = (char *)malloc(xattr_value_len);
1485 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1487 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
1488 if (xattr_value_len < 0) {
1491 retval = bxattr_exit_ok;
1494 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1495 jcr->last_fname, be.bstrerror());
1496 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1497 jcr->last_fname, be.bstrerror());
1503 * Store the actual length of the value.
1505 current_xattr->value_length = xattr_value_len;
1506 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1509 * Protect ourself against things getting out of hand.
1511 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1512 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1513 jcr->last_fname, MAX_XATTR_STREAM);
1519 if (xattr_value_list == NULL) {
1520 xattr_value_list = New(alist(10, not_owned_by_alist));
1523 xattr_value_list->append(current_xattr);
1524 current_xattr = NULL;
1530 * Drop the local copy of the current_attrnamespace.
1532 actuallyfree(current_attrnamespace);
1533 current_attrnamespace = NULL;
1536 * We are done with this xattr list.
1539 xattr_list = (char *)NULL;
1543 * If we found any xattr send them to the SD.
1545 if (xattr_count > 0) {
1547 * Serialize the datastream.
1549 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1550 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1552 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1558 * Send the datastream to the SD.
1560 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1562 retval = bxattr_exit_ok;
1566 if (current_attrnamespace != NULL) {
1567 actuallyfree(current_attrnamespace);
1569 if (current_xattr != NULL) {
1570 if (current_xattr->value != NULL) {
1571 free(current_xattr->value);
1573 if (current_xattr->name != NULL) {
1574 free(current_xattr->name);
1576 free(current_xattr);
1578 if (xattr_list != NULL) {
1581 if (xattr_value_list != NULL) {
1582 xattr_drop_internal_table(xattr_value_list);
1587 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
1589 xattr_t *current_xattr;
1590 alist *xattr_value_list;
1591 int current_attrnamespace, cnt;
1592 char *attrnamespace, *attrname;
1595 xattr_value_list = New(alist(10, not_owned_by_alist));
1597 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1598 xattr_drop_internal_table(xattr_value_list);
1599 return bxattr_exit_error;
1602 foreach_alist(current_xattr, xattr_value_list) {
1604 * Try splitting the xattr_name into a namespace and name part.
1605 * The splitting character is a .
1607 attrnamespace = current_xattr->name;
1608 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1609 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1610 current_xattr->name, jcr->last_fname);
1611 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1612 current_xattr->name, jcr->last_fname);
1618 * Make sure the attrnamespace makes sense.
1620 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1621 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1622 attrnamespace, jcr->last_fname);
1623 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1624 attrnamespace, jcr->last_fname);
1629 * Try restoring the extended attribute.
1631 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1632 attrname, current_xattr->value, current_xattr->value_length);
1633 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1639 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1640 jcr->last_fname, be.bstrerror());
1641 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1642 jcr->last_fname, be.bstrerror());
1649 xattr_drop_internal_table(xattr_value_list);
1650 return bxattr_exit_ok;
1653 xattr_drop_internal_table(xattr_value_list);
1654 return bxattr_exit_error;
1658 * Function pointers to the build and parse function to use for these xattrs.
1660 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1661 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1663 #elif defined(HAVE_OSF1_OS)
1665 #if !defined(HAVE_GETPROPLIST) || \
1666 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1667 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1668 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1669 !defined(HAVE_SETPROPLIST)
1670 #error "Missing full support for the Extended Attributes functions."
1673 #ifdef HAVE_SYS_PROPLIST_H
1674 #include <sys/proplist.h>
1676 #error "Missing sys/proplist.h header file"
1680 * Define the supported XATTR streams for this OS
1682 static int os_default_xattr_streams[1] = { STREAM_XATTR_TRU64 };
1683 static const char *xattr_acl_skiplist[1] = { NULL };
1684 static const char *xattr_skiplist[1] = { NULL };
1686 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1693 int xattr_count = 0;
1696 int32_t xattr_list_len,
1699 uint32_t expected_serialize_len = 0;
1700 xattr_t *current_xattr = NULL;
1701 alist *xattr_value_list = NULL;
1702 struct proplistname_args prop_args;
1703 bxattr_exit_code retval = bxattr_exit_error;
1704 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1707 xattrbuf_size = sizeof_pool_memory(xattrbuf);
1708 xattrbuf_min_size = 0;
1709 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1710 xattrbuf, &xattrbuf_min_size);
1713 * See what xattr are available.
1715 switch (xattr_list_len) {
1719 retval = bxattr_exit_ok;
1722 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1723 jcr->last_fname, be.bstrerror());
1724 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1725 jcr->last_fname, be.bstrerror());
1730 if (xattrbuf_min_size) {
1732 * The buffer isn't big enough to hold the xattr data, we now have
1733 * a minimum buffersize so we resize the buffer and try again.
1735 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1736 xattrbuf_size = xattrbuf_min_size + 1;
1737 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1738 xattrbuf, &xattrbuf_min_size);
1739 switch (xattr_list_len) {
1743 retval = bxattr_exit_ok;
1746 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1747 jcr->last_fname, be.bstrerror());
1748 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1749 jcr->last_fname, be.bstrerror());
1755 * This should never happen as we sized the buffer according to the minimumsize
1756 * returned by a previous getproplist call. If it does happen things are fishy and
1757 * we are better of forgetting this xattr as it seems its list is changing at this
1758 * exact moment so we can never make a good backup copy of it.
1760 retval = bxattr_exit_ok;
1769 retval = bxattr_exit_ok;
1778 * Walk the list of extended attributes names and retrieve the data.
1779 * We already count the bytes needed for serializing the stream later on.
1782 while (xattrbuf_size > 0) {
1784 * Call getproplist_entry to initialize name and value
1785 * pointers to entries position within buffer.
1787 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
1790 * On some OSes you also get the acls in the extented attribute list.
1791 * So we check if we are already backing up acls and if we do we
1792 * don't store the extended attribute with the same info.
1794 if (ff_pkt->flags & FO_ACL) {
1795 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1796 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
1804 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1807 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1808 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
1816 Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
1821 * Each xattr valuepair starts with a magic so we can parse it easier.
1823 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1824 current_xattr->magic = XATTR_MAGIC;
1825 expected_serialize_len += sizeof(current_xattr->magic);
1827 current_xattr->name_length = strlen(xattr_name);
1828 current_xattr->name = bstrdup(xattr_name);
1830 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1832 current_xattr->value_length = *xattr_value_len;
1833 current_xattr->value = (char *)malloc(current_xattr->value_length);
1834 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
1836 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1839 * Protect ourself against things getting out of hand.
1841 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1842 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1843 jcr->last_fname, MAX_XATTR_STREAM);
1847 if (xattr_value_list == NULL) {
1848 xattr_value_list = New(alist(10, not_owned_by_alist));
1851 xattr_value_list->append(current_xattr);
1852 current_xattr = NULL;
1857 * If we found any xattr send them to the SD.
1859 if (xattr_count > 0) {
1861 * Serialize the datastream.
1863 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1864 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1866 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1872 * Send the datastream to the SD.
1874 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1878 if (current_xattr != NULL) {
1879 if (current_xattr->value != NULL) {
1880 free(current_xattr->value);
1882 if (current_xattr->name != NULL) {
1883 free(current_xattr->name);
1885 free(current_xattr);
1887 if (xattr_value_list != NULL) {
1888 xattr_drop_internal_table(xattr_value_list);
1890 free_pool_memory(xattrbuf);
1895 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr, int stream)
1897 char *bp, *xattrbuf = NULL;
1898 int32_t xattrbuf_size, cnt;
1899 xattr_t *current_xattr;
1900 alist *xattr_value_list;
1901 bxattr_exit_code retval = bxattr_exit_error;
1904 xattr_value_list = New(alist(10, not_owned_by_alist));
1906 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1907 xattr_drop_internal_table(xattr_value_list);
1908 return bxattr_exit_error;
1912 * See how big the propertylist must be.
1915 foreach_alist(current_xattr, xattr_value_list) {
1916 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
1919 xattrbuf = (char *)malloc(xattrbuf_size);
1922 * Add all value pairs to the proplist.
1926 foreach_alist(current_xattr, xattr_value_list) {
1927 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
1928 current_xattr->value, &bp);
1934 if (cnt != xattrbuf_size) {
1935 Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
1937 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
1943 * Restore the list of extended attributes on the file.
1945 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
1950 retval = bxattr_exit_ok;
1953 Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
1954 jcr->last_fname, be.bstrerror());
1955 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
1956 jcr->last_fname, be.bstrerror());
1966 xattr_drop_internal_table(xattr_value_list);
1967 return bxattr_exit_ok;
1973 xattr_drop_internal_table(xattr_value_list);
1974 return bxattr_exit_error;
1978 * Function pointers to the build and parse function to use for these xattrs.
1980 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_xattr_streams;
1981 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = tru64_parse_xattr_streams;
1983 #elif defined(HAVE_SUN_OS)
1985 * Solaris extended attributes were introduced in Solaris 9
1988 * Solaris extensible attributes were introduced in OpenSolaris
1989 * by PSARC 2007/315 Solaris extensible attributes are also
1990 * sometimes called extended system attributes.
1992 * man fsattr(5) on Solaris gives a wealth of info. The most
1993 * important bits are:
1995 * Attributes are logically supported as files within the file
1996 * system. The file system is therefore augmented with an
1997 * orthogonal name space of file attributes. Any file (includ-
1998 * ing attribute files) can have an arbitrarily deep attribute
1999 * tree associated with it. Attribute values are accessed by
2000 * file descriptors obtained through a special attribute inter-
2001 * face. This logical view of "attributes as files" allows the
2002 * leveraging of existing file system interface functionality
2003 * to support the construction, deletion, and manipulation of
2006 * The special files "." and ".." retain their accustomed
2007 * semantics within the attribute hierarchy. The "." attribute
2008 * file refers to the current directory and the ".." attribute
2009 * file refers to the parent directory. The unnamed directory
2010 * at the head of each attribute tree is considered the "child"
2011 * of the file it is associated with and the ".." file refers
2012 * to the associated file. For any non-directory file with
2013 * attributes, the ".." entry in the unnamed directory refers
2014 * to a file that is not a directory.
2016 * Conceptually, the attribute model is fully general. Extended
2017 * attributes can be any type of file (doors, links, direc-
2018 * tories, and so forth) and can even have their own attributes
2019 * (fully recursive). As a result, the attributes associated
2020 * with a file could be an arbitrarily deep directory hierarchy
2021 * where each attribute could have an equally complex attribute
2022 * tree associated with it. Not all implementations are able
2023 * to, or want to, support the full model. Implementation are
2024 * therefore permitted to reject operations that are not sup-
2025 * ported. For example, the implementation for the UFS file
2026 * system allows only regular files as attributes (for example,
2027 * no sub-directories) and rejects attempts to place attributes
2030 * The following list details the operations that are rejected
2031 * in the current implementation:
2033 * link Any attempt to create links between
2034 * attribute and non-attribute space
2035 * is rejected to prevent security-
2036 * related or otherwise sensitive
2037 * attributes from being exposed, and
2038 * therefore manipulable, as regular
2041 * rename Any attempt to rename between
2042 * attribute and non-attribute space
2043 * is rejected to prevent an already
2044 * linked file from being renamed and
2045 * thereby circumventing the link res-
2048 * mkdir, symlink, mknod Any attempt to create a "non-
2049 * regular" file in attribute space is
2050 * rejected to reduce the functional-
2051 * ity, and therefore exposure and
2052 * risk, of the initial implementa-
2055 * The entire available name space has been allocated to "gen-
2056 * eral use" to bring the implementation in line with the NFSv4
2057 * draft standard [NFSv4]. That standard defines "named attri-
2058 * butes" (equivalent to Solaris Extended Attributes) with no
2059 * naming restrictions. All Sun applications making use of
2060 * opaque extended attributes will use the prefix "SUNW".
2063 #ifdef HAVE_SYS_ATTR_H
2064 #include <sys/attr.h>
2071 #ifdef HAVE_SYS_NVPAIR_H
2072 #include <sys/nvpair.h>
2075 #ifdef HAVE_SYS_ACL_H
2076 #include <sys/acl.h>
2079 #if !defined(HAVE_OPENAT) || \
2080 !defined(HAVE_UNLINKAT) || \
2081 !defined(HAVE_FCHOWNAT) || \
2082 !defined(HAVE_FUTIMESAT)
2083 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2087 * Define the supported XATTR streams for this OS
2089 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2090 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
2092 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
2093 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2096 * This code creates a temporary cache with entries for each xattr which has
2097 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2099 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2101 xattr_link_cache_entry_t *ptr;
2103 foreach_alist(ptr, jcr->xattr_data->link_cache) {
2104 if (ptr && ptr->inum == inum) {
2111 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2113 xattr_link_cache_entry_t *ptr;
2115 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2116 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
2118 bstrncpy(ptr->target, target, sizeof(ptr->target));
2119 jcr->xattr_data->link_cache->append(ptr);
2122 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2124 * This function returns true if a non default extended system attribute
2125 * list is associated with fd and returns false when an error has occured
2126 * or when only extended system attributes other than archive,
2127 * av_modified or crtime are set.
2129 * The function returns true for the following cases:
2131 * - any extended system attribute other than the default attributes
2132 * ('archive', 'av_modified' and 'crtime') is set
2133 * - nvlist has NULL name string
2134 * - nvpair has data type of 'nvlist'
2135 * - default data type.
2137 static bool solaris_has_non_transient_extensible_attributes(int fd)
2145 bool retval = false;
2147 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2152 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2153 name = nvpair_name(pair);
2156 fattr = name_to_attr(name);
2162 type = nvpair_type(pair);
2164 case DATA_TYPE_BOOLEAN_VALUE:
2165 if (nvpair_value_boolean_value(pair, &value) != 0) {
2168 if (value && fattr != F_ARCHIVE &&
2169 fattr != F_AV_MODIFIED) {
2174 case DATA_TYPE_UINT64_ARRAY:
2175 if (fattr != F_CRTIME) {
2180 case DATA_TYPE_NVLIST:
2188 if (response != NULL) {
2189 nvlist_free(response);
2193 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2195 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2197 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2198 * There is no need to store those acls as we already store the stat bits too.
2200 static bool acl_is_trivial(int count, aclent_t *entries)
2205 for (n = 0; n < count; n++) {
2207 if (!(ace->a_type == USER_OBJ ||
2208 ace->a_type == GROUP_OBJ ||
2209 ace->a_type == OTHER_OBJ ||
2210 ace->a_type == CLASS_OBJ))
2215 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2217 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2220 #ifdef HAVE_EXTENDED_ACL
2226 * See if this attribute has an ACL
2228 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2229 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2231 * See if there is a non trivial acl on the file.
2233 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2234 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2237 return bxattr_exit_ok;
2239 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2240 attrname, jcr->last_fname, be.bstrerror());
2241 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2242 attrname, jcr->last_fname, be.bstrerror());
2243 return bxattr_exit_error;
2248 #if defined(ACL_SID_FMT)
2250 * New format flag added in newer Solaris versions.
2252 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2254 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2255 #endif /* ACL_SID_FMT */
2257 *acl_text = acl_totext(aclp, flags);
2265 return bxattr_exit_ok;
2266 #else /* HAVE_EXTENDED_ACL */
2268 aclent_t *acls = NULL;
2272 * See if this attribute has an ACL
2275 n = facl(fd, GETACLCNT, 0, NULL);
2277 n = acl(attrname, GETACLCNT, 0, NULL);
2280 if (n >= MIN_ACL_ENTRIES) {
2281 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2282 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2283 acl(attrname, GETACL, n, acls) != n) {
2287 return bxattr_exit_ok;
2289 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2290 attrname, jcr->last_fname, be.bstrerror());
2291 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2292 attrname, jcr->last_fname, be.bstrerror());
2294 return bxattr_exit_error;
2299 * See if there is a non trivial acl on the file.
2301 if (!acl_is_trivial(n, acls)) {
2302 if ((*acl_text = acltotext(acls, n)) == NULL) {
2303 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2304 attrname, jcr->last_fname, be.bstrerror());
2305 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2306 attrname, jcr->last_fname, be.bstrerror());
2308 return bxattr_exit_error;
2318 return bxattr_exit_ok;
2319 #endif /* HAVE_EXTENDED_ACL */
2321 #else /* HAVE_ACL */
2322 return bxattr_exit_ok;
2323 #endif /* HAVE_ACL */
2327 * Forward declaration for recursive function call.
2329 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2332 * Save an extended or extensible attribute.
2333 * This is stored as an opaque stream of bytes with the following encoding:
2335 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2337 * or for a hardlinked or symlinked attribute
2339 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2341 * xattr_name can be a subpath relative to the file the xattr is on.
2342 * stat_buffer is the string representation of the stat struct.
2343 * acl_string is an acl text when a non trivial acl is set on the xattr.
2344 * actual_xattr_data is the content of the xattr file.
2346 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2347 const char *attrname, bool toplevel_hidden_dir, int stream)
2352 xattr_link_cache_entry_t *xlce;
2353 char target_attrname[PATH_MAX];
2354 char link_source[PATH_MAX];
2355 char *acl_text = NULL;
2356 char attribs[MAXSTRING];
2357 char buffer[XATTR_BUFSIZ];
2358 bxattr_exit_code retval = bxattr_exit_error;
2361 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2364 * Get the stats of the extended or extensible attribute.
2366 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2369 retval = bxattr_exit_ok;
2372 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2373 target_attrname, jcr->last_fname, be.bstrerror());
2374 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2375 target_attrname, jcr->last_fname, be.bstrerror());
2381 * Based on the filetype perform the correct action. We support most filetypes here, more
2382 * then the actual implementation on Solaris supports so some code may never get executed
2383 * due to limitations in the implementation.
2385 switch (st.st_mode & S_IFMT) {
2390 * Get any acl on the xattr.
2392 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2396 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2397 * Encode the stat struct into an ASCII representation.
2399 encode_stat(attribs, &st, 0, stream);
2400 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2401 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2405 * Get any acl on the xattr.
2407 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2411 * See if this is the toplevel_hidden_dir being saved.
2413 if (toplevel_hidden_dir) {
2415 * Save the data for later storage when we encounter a real xattr. We store the data
2416 * in the jcr->xattr_data->content buffer and flush that just before sending out the
2417 * first real xattr. Encode the stat struct into an ASCII representation and jump
2418 * out of the function.
2420 encode_stat(attribs, &st, 0, stream);
2421 cnt = bsnprintf(buffer, sizeof(buffer),
2423 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2424 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2425 jcr->xattr_data->content_length = cnt;
2429 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2430 * Encode the stat struct into an ASCII representation.
2432 encode_stat(attribs, &st, 0, stream);
2433 cnt = bsnprintf(buffer, sizeof(buffer),
2435 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2440 * If this is a hardlinked file check the inode cache for a hit.
2442 if (st.st_nlink > 1) {
2444 * See if the cache already knows this inode number.
2446 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2448 * Generate a xattr encoding with the reference to the target in there.
2450 encode_stat(attribs, &st, st.st_ino, stream);
2451 cnt = bsnprintf(buffer, sizeof(buffer),
2453 target_attrname, 0, attribs, 0, xlce->target, 0);
2454 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2455 jcr->xattr_data->content_length = cnt;
2456 retval = send_xattr_stream(jcr, stream);
2459 * For a hard linked file we are ready now, no need to recursively save the attributes.
2465 * Store this hard linked file in the cache.
2466 * Store the name relative to the top level xattr space.
2468 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2472 * Get any acl on the xattr.
2474 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2479 * Encode the stat struct into an ASCII representation.
2481 encode_stat(attribs, &st, 0, stream);
2482 cnt = bsnprintf(buffer, sizeof(buffer),
2484 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2487 * Open the extended or extensible attribute file.
2489 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2492 retval = bxattr_exit_ok;
2495 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2496 target_attrname, jcr->last_fname, be.bstrerror());
2497 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2498 target_attrname, jcr->last_fname, be.bstrerror());
2505 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2506 * Encode the stat struct into an ASCII representation.
2508 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2511 retval = bxattr_exit_ok;
2514 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2515 target_attrname, jcr->last_fname, be.bstrerror());
2516 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2517 target_attrname, jcr->last_fname, be.bstrerror());
2523 * Generate a xattr encoding with the reference to the target in there.
2525 encode_stat(attribs, &st, st.st_ino, stream);
2526 cnt = bsnprintf(buffer, sizeof(buffer),
2528 target_attrname, 0, attribs, 0, link_source, 0);
2529 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2530 jcr->xattr_data->content_length = cnt;
2531 retval = send_xattr_stream(jcr, stream);
2533 if (retval == bxattr_exit_ok) {
2534 jcr->xattr_data->nr_saved++;
2538 * For a soft linked file we are ready now, no need to recursively save the attributes.
2546 * See if this is the first real xattr being saved.
2547 * If it is save the toplevel_hidden_dir attributes first.
2548 * This is easy as its stored already in the jcr->xattr_data->content buffer.
2550 if (jcr->xattr_data->nr_saved == 0) {
2551 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2552 if (retval != bxattr_exit_ok) {
2555 jcr->xattr_data->nr_saved++;
2558 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2559 jcr->xattr_data->content_length = cnt;
2562 * Only dump the content of regular files.
2564 switch (st.st_mode & S_IFMT) {
2566 if (st.st_size > 0) {
2568 * Protect ourself against things getting out of hand.
2570 if (st.st_size >= MAX_XATTR_STREAM) {
2571 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2572 jcr->last_fname, MAX_XATTR_STREAM);
2576 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2577 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
2578 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
2579 jcr->xattr_data->content_length += cnt;
2583 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
2584 target_attrname, jcr->last_fname);
2585 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2586 target_attrname, jcr->last_fname);
2597 retval = send_xattr_stream(jcr, stream);
2598 if (retval == bxattr_exit_ok) {
2599 jcr->xattr_data->nr_saved++;
2604 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2605 * available on this extended attribute.
2608 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2611 * The recursive call could change our working dir so change back to the wanted workdir.
2613 if (fchdir(fd) < 0) {
2616 retval = bxattr_exit_ok;
2619 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2620 jcr->last_fname, be.bstrerror());
2621 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2622 jcr->last_fname, fd, be.bstrerror());
2629 if (acl_text != NULL) {
2638 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2641 int fd, filefd = -1, attrdirfd = -1;
2644 char current_xattr_namespace[PATH_MAX];
2645 bxattr_exit_code retval = bxattr_exit_error;
2649 * Determine what argument to use. Use attr_parent when set
2650 * (recursive call) or jcr->last_fname for first call. Also save
2651 * the current depth of the xattr_space we are in.
2655 if (xattr_namespace) {
2656 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2657 xattr_namespace, attr_parent);
2659 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2662 name = jcr->last_fname;
2663 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2667 * Open the file on which to save the xattrs read-only.
2669 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2672 retval = bxattr_exit_ok;
2675 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2676 jcr->last_fname, be.bstrerror());
2677 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2678 jcr->last_fname, be.bstrerror());
2684 * Open the xattr naming space.
2686 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2690 * Gentile way of the system saying this type of xattr layering is not supported.
2691 * Which is not problem we just forget about this this xattr.
2692 * But as this is not an error we return a positive return value.
2694 retval = bxattr_exit_ok;
2697 retval = bxattr_exit_ok;
2700 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2701 name, jcr->last_fname, be.bstrerror());
2702 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2703 name, jcr->last_fname, be.bstrerror());
2709 * We need to change into the attribute directory to determine if each of the
2710 * attributes should be saved.
2712 if (fchdir(attrdirfd) < 0) {
2713 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2714 jcr->last_fname, be.bstrerror());
2715 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2716 jcr->last_fname, attrdirfd, be.bstrerror());
2721 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2722 * else because the readdir returns "." entry after the extensible attr entry.
2723 * And as we want this entry before anything else we better just save its data.
2726 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2727 true, STREAM_XATTR_SOLARIS);
2729 if ((fd = dup(attrdirfd)) == -1 ||
2730 (dirp = fdopendir(fd)) == (DIR *)NULL) {
2731 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2732 jcr->last_fname, be.bstrerror());
2733 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
2734 jcr->last_fname, fd, be.bstrerror());
2740 * Walk the namespace.
2742 while ((dp = readdir(dirp)) != NULL) {
2744 * Skip only the toplevel . dir.
2746 if (!attr_parent && bstrcmp(dp->d_name, "."))
2750 * Skip all .. directories
2752 if (bstrcmp(dp->d_name, ".."))
2755 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2756 current_xattr_namespace, dp->d_name, jcr->last_fname);
2758 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2760 * We are not interested in read-only extensible attributes.
2762 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2763 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2764 current_xattr_namespace, dp->d_name, jcr->last_fname);
2770 * We are only interested in read-write extensible attributes
2771 * when they contain non-transient values.
2773 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2775 * Determine if there are non-transient system attributes at the toplevel.
2776 * We need to provide a fd to the open file.
2778 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2779 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2780 current_xattr_namespace, dp->d_name, jcr->last_fname);
2787 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2788 false, STREAM_XATTR_SOLARIS_SYS);
2791 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2796 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2797 false, STREAM_XATTR_SOLARIS);
2801 retval = bxattr_exit_ok;
2804 if (attrdirfd != -1)
2812 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
2814 #ifdef HAVE_EXTENDED_ACL
2819 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
2820 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
2822 return bxattr_exit_error;
2825 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
2826 acl_set(attrname, aclp) != 0) {
2827 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2828 attrname, jcr->last_fname, be.bstrerror());
2829 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2830 attrname, jcr->last_fname, be.bstrerror());
2831 return bxattr_exit_error;
2837 return bxattr_exit_ok;
2839 #else /* HAVE_EXTENDED_ACL */
2841 aclent_t *acls = NULL;
2844 acls = aclfromtext(acl_text, &n);
2846 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
2847 acl(attrname, SETACL, n, acls) != 0) {
2848 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2849 attrname, jcr->last_fname, be.bstrerror());
2850 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2851 attrname, jcr->last_fname, be.bstrerror());
2852 return bxattr_exit_error;
2859 return bxattr_exit_ok;
2861 #endif /* HAVE_EXTENDED_ACL */
2864 #endif /* HAVE_ACL */
2866 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
2868 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
2869 int used_bytes, total_bytes, cnt;
2870 char *bp, *target_attrname, *attribs;
2871 char *linked_target = NULL;
2872 char *acl_text = NULL;
2876 struct timeval times[2];
2877 bxattr_exit_code retval = bxattr_exit_error;
2881 * Parse the xattr stream. First the part that is the same for all xattrs.
2884 total_bytes = jcr->xattr_data->content_length;
2887 * The name of the target xattr has a leading / we are not interested
2888 * in that so skip it when decoding the string. We always start a the /
2889 * of the xattr space anyway.
2891 target_attrname = jcr->xattr_data->content + 1;
2892 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
2893 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2899 * Open the file on which to restore the xattrs read-only.
2901 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
2902 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2903 jcr->last_fname, be.bstrerror());
2904 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2905 jcr->last_fname, be.bstrerror());
2910 * Open the xattr naming space and make it the current working dir.
2912 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2913 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
2914 jcr->last_fname, be.bstrerror());
2915 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
2916 jcr->last_fname, be.bstrerror());
2920 if (fchdir(attrdirfd) < 0) {
2921 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2922 jcr->last_fname, be.bstrerror());
2923 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2924 jcr->last_fname, attrdirfd, be.bstrerror());
2929 * Try to open the correct xattr subdir based on the target_attrname given.
2930 * e.g. check if its a subdir attrname. Each / in the string makes us go
2933 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2936 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2937 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2938 target_attrname, jcr->last_fname, be.bstrerror());
2939 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2940 target_attrname, jcr->last_fname, be.bstrerror());
2948 * Open the xattr naming space.
2950 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2951 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2952 target_attrname, jcr->last_fname, be.bstrerror());
2953 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2954 target_attrname, jcr->last_fname, be.bstrerror());
2962 * Make the xattr space our current workingdir.
2964 if (fchdir(attrdirfd) < 0) {
2965 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2966 target_attrname, jcr->last_fname, be.bstrerror());
2967 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2968 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2972 target_attrname = ++bp;
2976 * Decode the attributes from the stream.
2978 decode_stat(attribs, &st, &inum);
2981 * Decode the next field (acl_text).
2983 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2984 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2990 * Based on the filetype perform the correct action. We support most filetypes here, more
2991 * then the actual implementation on Solaris supports so some code may never get executed
2992 * due to limitations in the implementation.
2994 switch (st.st_mode & S_IFMT) {
2997 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2999 unlinkat(attrdirfd, target_attrname, 0);
3000 if (mkfifo(target_attrname, st.st_mode) < 0) {
3001 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3002 target_attrname, jcr->last_fname, be.bstrerror());
3003 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
3004 target_attrname, jcr->last_fname, be.bstrerror());
3011 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3013 unlinkat(attrdirfd, target_attrname, 0);
3014 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3015 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3016 target_attrname, jcr->last_fname, be.bstrerror());
3017 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3018 target_attrname, jcr->last_fname, be.bstrerror());
3024 * If its not the hidden_dir create the entry.
3025 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3027 if (!bstrcmp(target_attrname, ".")) {
3028 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3029 if (mkdir(target_attrname, st.st_mode) < 0) {
3030 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3031 target_attrname, jcr->last_fname, be.bstrerror());
3032 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3033 target_attrname, jcr->last_fname, be.bstrerror());
3040 * See if this is a hard linked file. e.g. inum != 0
3045 unlinkat(attrdirfd, target_attrname, 0);
3046 if (link(linked_target, target_attrname) < 0) {
3047 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3048 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3049 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3050 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3055 * Successfully restored xattr.
3057 retval = bxattr_exit_ok;
3060 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3061 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
3065 if (used_bytes < (total_bytes - 1))
3069 * Restore the actual xattr.
3071 if (!is_extensible) {
3072 unlinkat(attrdirfd, target_attrname, 0);
3075 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3076 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3077 target_attrname, jcr->last_fname, be.bstrerror());
3078 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3079 target_attrname, jcr->last_fname, be.bstrerror());
3085 * Restore the actual data.
3087 if (st.st_size > 0) {
3088 used_bytes = (data - jcr->xattr_data->content);
3089 cnt = total_bytes - used_bytes;
3092 * Do a sanity check, the st.st_size should be the same as the number of bytes
3093 * we have available as data of the stream.
3095 if (cnt != st.st_size) {
3096 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3097 target_attrname, jcr->last_fname);
3098 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3099 target_attrname, jcr->last_fname);
3104 cnt = write(attrfd, data, cnt);
3106 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3107 target_attrname, jcr->last_fname, be.bstrerror());
3108 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3109 target_attrname, jcr->last_fname, be.bstrerror());
3115 cnt = total_bytes - used_bytes;
3121 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3125 if (symlink(linked_target, target_attrname) < 0) {
3126 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3127 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3128 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3129 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3134 * Successfully restored xattr.
3136 retval = bxattr_exit_ok;
3143 * Restore owner and acl for non extensible attributes.
3145 if (!is_extensible) {
3146 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3150 * Gentile way of the system saying this type of xattr layering is not supported.
3151 * But as this is not an error we return a positive return value.
3153 retval = bxattr_exit_ok;
3156 retval = bxattr_exit_ok;
3159 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3160 target_attrname, jcr->last_fname, be.bstrerror());
3161 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3162 target_attrname, jcr->last_fname, be.bstrerror());
3169 if (acl_text && *acl_text)
3170 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3172 #endif /* HAVE_ACL */
3175 * For a non extensible attribute restore access and modification time on the xattr.
3177 if (!is_extensible) {
3178 times[0].tv_sec = st.st_atime;
3179 times[0].tv_usec = 0;
3180 times[1].tv_sec = st.st_mtime;
3181 times[1].tv_usec = 0;
3183 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3184 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3185 target_attrname, jcr->last_fname, be.bstrerror());
3186 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3187 target_attrname, jcr->last_fname, be.bstrerror());
3193 * Successfully restored xattr.
3195 retval = bxattr_exit_ok;
3199 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3201 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3208 if (attrdirfd != -1) {
3217 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3220 bxattr_exit_code retval = bxattr_exit_ok;
3223 * First see if extended attributes or extensible attributes are present.
3224 * If not just pretend things went ok.
3226 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3227 jcr->xattr_data->nr_saved = 0;
3228 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
3231 * As we change the cwd in the save function save the current cwd
3232 * for restore after return from the solaris_save_xattrs function.
3234 getcwd(cwd, sizeof(cwd));
3235 retval = solaris_save_xattrs(jcr, NULL, NULL);
3237 delete jcr->xattr_data->link_cache;
3238 jcr->xattr_data->link_cache = NULL;
3243 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
3246 bool is_extensible = false;
3247 bxattr_exit_code retval;
3250 * First make sure we can restore xattr on the filesystem.
3253 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3254 case STREAM_XATTR_SOLARIS_SYS:
3255 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3256 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
3257 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3259 return bxattr_exit_error;
3262 is_extensible = true;
3265 case STREAM_XATTR_SOLARIS:
3266 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3267 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
3268 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3270 return bxattr_exit_error;
3274 return bxattr_exit_error;
3278 * As we change the cwd in the restore function save the current cwd
3279 * for restore after return from the solaris_restore_xattrs function.
3281 getcwd(cwd, sizeof(cwd));
3282 retval = solaris_restore_xattrs(jcr, is_extensible);
3289 * Function pointers to the build and parse function to use for these xattrs.
3291 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
3292 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
3294 #endif /* defined(HAVE_SUN_OS) */
3297 * Entry points when compiled with support for XATTRs on a supported platform.
3299 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3301 if (os_build_xattr_streams) {
3302 return (*os_build_xattr_streams)(jcr, ff_pkt);
3304 return bxattr_exit_error;
3307 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
3311 if (os_parse_xattr_streams) {
3313 * See if we can parse this stream, and ifso give it a try.
3315 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3316 if (os_default_xattr_streams[cnt] == stream) {
3317 return (*os_parse_xattr_streams)(jcr, stream);
3322 * Issue a warning and discard the message. But pretend the restore was ok.
3324 Jmsg2(jcr, M_WARNING, 0,
3325 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3326 jcr->last_fname, stream);
3327 return bxattr_exit_error;