2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2011 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Functions to handle Extended Attributes for bacula.
31 * Extended Attributes are so OS specific we only restore Extended Attributes if
32 * they were saved using a filed on the same platform.
34 * Currently we support the following OSes:
35 * - AIX (Extended Attributes)
36 * - Darwin (Extended Attributes)
37 * - FreeBSD (Extended Attributes)
38 * - IRIX (Extended Attributes)
39 * - Linux (Extended Attributes)
40 * - NetBSD (Extended Attributes)
41 * - OpenBSD (Extended Attributes)
42 * (As it seems either they never implemented xattr or they are removed
43 * the support as it stated it was in version 3.1 but the current syscall
44 * tabled shows the extattr_ functions are not implemented. So as such we
45 * might eventually support xattr on OpenBSD when they implemented them using
46 * the same interface as FreeBSD and NetBSD.
47 * - Solaris (Extended Attributes and Extensible Attributes)
48 * - Tru64 (Extended Attributes)
50 * Written by Marco van Wieringen, November MMVIII
56 #if !defined(HAVE_XATTR)
58 * Entry points when compiled without support for XATTRs or on an unsupported platform.
60 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
62 return bxattr_exit_fatal;
65 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
67 return bxattr_exit_fatal;
71 * Send a XATTR stream to the SD.
73 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
75 BSOCK *sd = jcr->store_bsock;
77 #ifdef FD_NO_SEND_TEST
78 return bxattr_exit_ok;
84 if (jcr->xattr_data->content_length <= 0) {
85 return bxattr_exit_ok;
91 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
92 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
94 return bxattr_exit_fatal;
98 * Send the buffer to the storage deamon
100 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
102 sd->msg = jcr->xattr_data->content;
103 sd->msglen = jcr->xattr_data->content_length;
107 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
109 return bxattr_exit_fatal;
112 jcr->JobBytes += sd->msglen;
114 if (!sd->signal(BNET_EOD)) {
115 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
117 return bxattr_exit_fatal;
119 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
120 return bxattr_exit_ok;
124 * First some generic functions for OSes that use the same xattr encoding scheme.
125 * Currently for all OSes except for Solaris.
127 #if !defined(HAVE_SUN_OS)
128 static void xattr_drop_internal_table(alist *xattr_value_list)
130 xattr_t *current_xattr;
133 * Walk the list of xattrs and free allocated memory on traversing.
135 foreach_alist(current_xattr, xattr_value_list) {
137 * See if we can shortcut.
139 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
142 free(current_xattr->name);
144 if (current_xattr->value_length > 0)
145 free(current_xattr->value);
150 delete xattr_value_list;
154 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
155 * which encodes one or more xattr_t structures.
157 * The Serialized stream consists of the following elements:
158 * magic - A magic string which makes it easy to detect any binary incompatabilites
159 * name_length - The length of the following xattr name
160 * name - The name of the extended attribute
161 * value_length - The length of the following xattr data
162 * value - The actual content of the extended attribute
164 * This is repeated 1 or more times.
167 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, alist *xattr_value_list)
169 xattr_t *current_xattr;
173 * Make sure the serialized stream fits in the poolmem buffer.
174 * We allocate some more to be sure the stream is gonna fit.
176 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
177 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
180 * Walk the list of xattrs and serialize the data.
182 foreach_alist(current_xattr, xattr_value_list) {
184 * See if we can shortcut.
186 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
189 ser_uint32(current_xattr->magic);
190 ser_uint32(current_xattr->name_length);
191 ser_bytes(current_xattr->name, current_xattr->name_length);
193 ser_uint32(current_xattr->value_length);
194 if (current_xattr->value_length > 0 && current_xattr->value) {
195 ser_bytes(current_xattr->value, current_xattr->value_length);
197 Dmsg3(100, "Backup xattr named %s, value %*s\n",
198 current_xattr->name, current_xattr->value, current_xattr->value);
200 Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
204 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
205 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
207 return jcr->xattr_data->content_length;
210 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
213 xattr_t *current_xattr;
214 bxattr_exit_code retval = bxattr_exit_ok;
217 * Parse the stream and call restore_xattr_on_file for each extended attribute.
219 * Start unserializing the data. We keep on looping while we have not
220 * unserialized all bytes in the stream.
222 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
223 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
225 * First make sure the magic is present. This way we can easily catch corruption.
226 * Any missing MAGIC is fatal we do NOT try to continue.
228 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
229 unser_uint32(current_xattr->magic);
230 if (current_xattr->magic != XATTR_MAGIC) {
231 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
233 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
236 return bxattr_exit_error;
240 * Decode the valuepair. First decode the length of the name.
242 unser_uint32(current_xattr->name_length);
243 if (current_xattr->name_length == 0) {
244 Mmsg1(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
246 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
249 return bxattr_exit_error;
253 * Allocate room for the name and decode its content.
255 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
256 unser_bytes(current_xattr->name, current_xattr->name_length);
259 * The xattr_name needs to be null terminated.
261 current_xattr->name[current_xattr->name_length] = '\0';
264 * Decode the value length.
266 unser_uint32(current_xattr->value_length);
268 if (current_xattr->value_length > 0) {
270 * Allocate room for the value and decode its content.
272 current_xattr->value = (char *)malloc(current_xattr->value_length);
273 unser_bytes(current_xattr->value, current_xattr->value_length);
275 Dmsg3(100, "Restoring xattr named %s, value %*s\n",
276 current_xattr->name, current_xattr->value, current_xattr->value);
278 current_xattr->value = NULL;
279 Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
282 xattr_value_list->append(current_xattr);
285 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
291 * This is a supported OS, See what kind of interface we should use.
293 #if defined(HAVE_AIX_OS)
295 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
296 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
297 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
298 #error "Missing full support for the Extended Attributes (EA) functions."
304 #error "Missing sys/ea.h header file"
308 * Define the supported XATTR streams for this OS
310 static int os_default_xattr_streams[1] = { STREAM_XATTR_AIX };
313 * Fallback to the non l-functions when those are not available.
315 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
318 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
321 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
322 #define llistea listea
325 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
328 char *xattr_list, *bp;
329 int cnt, xattr_count = 0;
330 uint32_t name_length;
331 int32_t xattr_list_len,
333 uint32_t expected_serialize_len = 0;
334 xattr_t *current_xattr = NULL;
335 alist *xattr_value_list = NULL;
336 bxattr_exit_code retval = bxattr_exit_error;
340 * First get the length of the available list with extended attributes.
342 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
343 switch (xattr_list_len) {
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) {
971 return bxattr_exit_ok;
973 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
974 jcr->last_fname, be.bstrerror());
975 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
976 jcr->last_fname, be.bstrerror());
977 return bxattr_exit_error;
981 return bxattr_exit_ok;
987 * Allocate room for the extented attribute list.
989 xattr_list = (char *)malloc(xattr_list_len + 1);
990 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
993 * Get the actual list of extended attributes names for a file.
995 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
996 switch (xattr_list_len) {
1002 retval = bxattr_exit_ok;
1005 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
1006 jcr->last_fname, be.bstrerror());
1007 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
1008 jcr->last_fname, be.bstrerror());
1015 xattr_list[xattr_list_len] = '\0';
1018 * Walk the list of extended attributes names and retrieve the data.
1019 * We already count the bytes needed for serializing the stream later on.
1022 while ((bp - xattr_list) + 1 < xattr_list_len) {
1026 * On some OSes you also get the acls in the extented attribute list.
1027 * So we check if we are already backing up acls and if we do we
1028 * don't store the extended attribute with the same info.
1030 if (ff_pkt->flags & FO_ACL) {
1031 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1032 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1040 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1043 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1044 if (bstrcmp(bp, xattr_skiplist[cnt])) {
1051 name_length = strlen(bp);
1052 if (skip_xattr || name_length == 0) {
1053 Dmsg1(100, "Skipping xattr named %s\n", bp);
1054 bp = strchr(bp, '\0') + 1;
1059 * Each xattr valuepair starts with a magic so we can parse it easier.
1061 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1062 current_xattr->magic = XATTR_MAGIC;
1063 expected_serialize_len += sizeof(current_xattr->magic);
1066 * Allocate space for storing the name.
1068 current_xattr->name_length = name_length;
1069 current_xattr->name = (char *)malloc(current_xattr->name_length);
1070 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
1072 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1075 * First see how long the value is for the extended attribute.
1077 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1078 switch (xattr_value_len) {
1084 retval = bxattr_exit_ok;
1087 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1088 jcr->last_fname, be.bstrerror());
1089 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1090 jcr->last_fname, be.bstrerror());
1095 current_xattr->value = NULL;
1096 current_xattr->value_length = 0;
1097 expected_serialize_len += sizeof(current_xattr->value_length);
1101 * Allocate space for storing the value.
1103 current_xattr->value = (char *)malloc(xattr_value_len);
1104 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1106 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1107 if (xattr_value_len < 0) {
1112 retval = bxattr_exit_ok;
1115 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1116 jcr->last_fname, be.bstrerror());
1117 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1118 jcr->last_fname, be.bstrerror());
1123 * Store the actual length of the value.
1125 current_xattr->value_length = xattr_value_len;
1126 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1129 * Protect ourself against things getting out of hand.
1131 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1132 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1133 jcr->last_fname, MAX_XATTR_STREAM);
1138 if (xattr_value_list == NULL) {
1139 xattr_value_list = New(alist(10, not_owned_by_alist));
1142 xattr_value_list->append(current_xattr);
1143 current_xattr = NULL;
1145 bp = strchr(bp, '\0') + 1;
1150 xattr_list = (char *)NULL;
1153 * If we found any xattr send them to the SD.
1155 if (xattr_count > 0) {
1157 * Serialize the datastream.
1159 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1160 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1162 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1168 * Send the datastream to the SD.
1170 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1172 retval = bxattr_exit_ok;
1176 if (current_xattr != NULL) {
1177 if (current_xattr->value != NULL) {
1178 free(current_xattr->value);
1180 if (current_xattr->name != NULL) {
1181 free(current_xattr->name);
1183 free(current_xattr);
1185 if (xattr_list != NULL) {
1188 if (xattr_value_list != NULL) {
1189 xattr_drop_internal_table(xattr_value_list);
1194 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
1196 xattr_t *current_xattr;
1197 alist *xattr_value_list;
1200 xattr_value_list = New(alist(10, not_owned_by_alist));
1202 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1203 xattr_drop_internal_table(xattr_value_list);
1204 return bxattr_exit_error;
1207 foreach_alist(current_xattr, xattr_value_list) {
1208 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1215 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
1216 jcr->last_fname, be.bstrerror());
1217 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1218 jcr->last_fname, be.bstrerror());
1224 xattr_drop_internal_table(xattr_value_list);
1225 return bxattr_exit_ok;
1228 xattr_drop_internal_table(xattr_value_list);
1229 return bxattr_exit_error;
1233 * Function pointers to the build and parse function to use for these xattrs.
1235 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
1236 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
1238 #elif defined(HAVE_FREEBSD_OS) || \
1239 defined(HAVE_NETBSD_OS) || \
1240 defined(HAVE_OPENBSD_OS)
1242 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1243 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1244 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1245 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1246 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1247 #error "Missing full support for the extattr functions."
1250 #ifdef HAVE_SYS_EXTATTR_H
1251 #include <sys/extattr.h>
1253 #error "Missing sys/extattr.h header file"
1256 #ifdef HAVE_LIBUTIL_H
1257 #include <libutil.h>
1260 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1261 #define extattr_get_link extattr_get_file
1263 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1264 #define extattr_set_link extattr_set_file
1266 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1267 #define extattr_list_link extattr_list_file
1270 #if defined(HAVE_FREEBSD_OS)
1271 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
1272 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1273 static const char *xattr_acl_skiplist[4] = { "system.posix1e.acl_access", "system.posix1e.acl_default", "system.nfs4.acl", NULL };
1274 static const char *xattr_skiplist[1] = { NULL };
1275 #elif defined(HAVE_NETBSD_OS)
1276 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
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 };
1280 #elif defined(HAVE_OPENBSD_OS)
1281 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
1282 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1283 static const char *xattr_acl_skiplist[1] = { NULL };
1284 static const char *xattr_skiplist[1] = { NULL };
1287 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1291 int cnt, index, xattr_count = 0;
1292 int32_t xattr_list_len,
1294 uint32_t expected_serialize_len = 0;
1295 unsigned int namespace_index;
1297 char *current_attrnamespace = NULL;
1298 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1299 xattr_t *current_xattr = NULL;
1300 alist *xattr_value_list = NULL;
1301 bxattr_exit_code retval = bxattr_exit_error;
1305 * Loop over all available xattr namespaces.
1307 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
1308 attrnamespace = os_default_xattr_namespaces[namespace_index];
1311 * First get the length of the available list with extended attributes.
1312 * If we get EPERM on system namespace, don't return error.
1313 * This is expected for normal users trying to archive the system
1314 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1315 * they've decided to return EOPNOTSUPP instead.
1317 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1318 switch (xattr_list_len) {
1322 retval = bxattr_exit_ok;
1324 #if defined(EOPNOTSUPP)
1328 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1335 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1336 jcr->last_fname, be.bstrerror());
1337 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1338 jcr->last_fname, be.bstrerror());
1349 * Allocate room for the extented attribute list.
1351 xattr_list = (char *)malloc(xattr_list_len + 1);
1352 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
1355 * Get the actual list of extended attributes names for a file.
1357 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
1358 switch (xattr_list_len) {
1362 retval = bxattr_exit_ok;
1365 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1366 jcr->last_fname, be.bstrerror());
1367 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1368 jcr->last_fname, be.bstrerror());
1375 xattr_list[xattr_list_len] = '\0';
1378 * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
1379 * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
1381 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1382 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
1383 attrnamespace, jcr->last_fname);
1384 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1385 attrnamespace, jcr->last_fname);
1390 * Walk the list of extended attributes names and retrieve the data.
1391 * We already count the bytes needed for serializing the stream later on.
1393 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1397 * Print the current name into the buffer as its not null terminated we need to
1398 * use the length encoded in the string for copying only the needed bytes.
1400 cnt = xattr_list[index];
1401 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1402 cnt = ((int)sizeof(current_attrname) - 1);
1404 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1405 current_attrname[cnt] = '\0';
1408 * First make a xattr tuple of the current namespace and the name of the xattr.
1409 * e.g. something like user.<attrname> or system.<attrname>
1411 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
1414 * On some OSes you also get the acls in the extented attribute list.
1415 * So we check if we are already backing up acls and if we do we
1416 * don't store the extended attribute with the same info.
1418 if (ff_pkt->flags & FO_ACL) {
1419 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1420 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1428 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1431 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1432 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1440 Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1445 * Each xattr valuepair starts with a magic so we can parse it easier.
1447 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1448 current_xattr->magic = XATTR_MAGIC;
1449 expected_serialize_len += sizeof(current_xattr->magic);
1452 * Allocate space for storing the name.
1454 current_xattr->name_length = strlen(current_attrtuple);
1455 current_xattr->name = (char *)malloc(current_xattr->name_length);
1456 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
1458 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1461 * First see how long the value is for the extended attribute.
1463 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
1464 switch (xattr_value_len) {
1468 retval = bxattr_exit_ok;
1471 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1472 jcr->last_fname, be.bstrerror());
1473 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1474 jcr->last_fname, be.bstrerror());
1479 current_xattr->value = NULL;
1480 current_xattr->value_length = 0;
1481 expected_serialize_len += sizeof(current_xattr->value_length);
1485 * Allocate space for storing the value.
1487 current_xattr->value = (char *)malloc(xattr_value_len);
1488 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1490 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
1491 if (xattr_value_len < 0) {
1494 retval = bxattr_exit_ok;
1497 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1498 jcr->last_fname, be.bstrerror());
1499 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1500 jcr->last_fname, be.bstrerror());
1506 * Store the actual length of the value.
1508 current_xattr->value_length = xattr_value_len;
1509 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1512 * Protect ourself against things getting out of hand.
1514 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1515 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1516 jcr->last_fname, MAX_XATTR_STREAM);
1522 if (xattr_value_list == NULL) {
1523 xattr_value_list = New(alist(10, not_owned_by_alist));
1526 xattr_value_list->append(current_xattr);
1527 current_xattr = NULL;
1533 * Drop the local copy of the current_attrnamespace.
1535 actuallyfree(current_attrnamespace);
1536 current_attrnamespace = NULL;
1539 * We are done with this xattr list.
1542 xattr_list = (char *)NULL;
1546 * If we found any xattr send them to the SD.
1548 if (xattr_count > 0) {
1550 * Serialize the datastream.
1552 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1553 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1555 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1561 * Send the datastream to the SD.
1563 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1565 retval = bxattr_exit_ok;
1569 if (current_attrnamespace != NULL) {
1570 actuallyfree(current_attrnamespace);
1572 if (current_xattr != NULL) {
1573 if (current_xattr->value != NULL) {
1574 free(current_xattr->value);
1576 if (current_xattr->name != NULL) {
1577 free(current_xattr->name);
1579 free(current_xattr);
1581 if (xattr_list != NULL) {
1584 if (xattr_value_list != NULL) {
1585 xattr_drop_internal_table(xattr_value_list);
1590 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
1592 xattr_t *current_xattr;
1593 alist *xattr_value_list;
1594 int current_attrnamespace, cnt;
1595 char *attrnamespace, *attrname;
1598 xattr_value_list = New(alist(10, not_owned_by_alist));
1600 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1601 xattr_drop_internal_table(xattr_value_list);
1602 return bxattr_exit_error;
1605 foreach_alist(current_xattr, xattr_value_list) {
1607 * Try splitting the xattr_name into a namespace and name part.
1608 * The splitting character is a .
1610 attrnamespace = current_xattr->name;
1611 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1612 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1613 current_xattr->name, jcr->last_fname);
1614 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1615 current_xattr->name, jcr->last_fname);
1621 * Make sure the attrnamespace makes sense.
1623 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1624 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1625 attrnamespace, jcr->last_fname);
1626 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1627 attrnamespace, jcr->last_fname);
1632 * Try restoring the extended attribute.
1634 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1635 attrname, current_xattr->value, current_xattr->value_length);
1636 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1642 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1643 jcr->last_fname, be.bstrerror());
1644 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1645 jcr->last_fname, be.bstrerror());
1652 xattr_drop_internal_table(xattr_value_list);
1653 return bxattr_exit_ok;
1656 xattr_drop_internal_table(xattr_value_list);
1657 return bxattr_exit_error;
1661 * Function pointers to the build and parse function to use for these xattrs.
1663 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1664 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1666 #elif defined(HAVE_OSF1_OS)
1668 #if !defined(HAVE_GETPROPLIST) || \
1669 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1670 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1671 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1672 !defined(HAVE_SETPROPLIST)
1673 #error "Missing full support for the Extended Attributes functions."
1676 #ifdef HAVE_SYS_PROPLIST_H
1677 #include <sys/proplist.h>
1679 #error "Missing sys/proplist.h header file"
1683 * Define the supported XATTR streams for this OS
1685 static int os_default_xattr_streams[1] = { STREAM_XATTR_TRU64 };
1686 static const char *xattr_acl_skiplist[1] = { NULL };
1687 static const char *xattr_skiplist[1] = { NULL };
1689 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1696 int xattr_count = 0;
1699 int32_t xattr_list_len,
1702 uint32_t expected_serialize_len = 0;
1703 xattr_t *current_xattr = NULL;
1704 alist *xattr_value_list = NULL;
1705 struct proplistname_args prop_args;
1706 bxattr_exit_code retval = bxattr_exit_error;
1707 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1710 xattrbuf_size = sizeof_pool_memory(xattrbuf);
1711 xattrbuf_min_size = 0;
1712 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1713 xattrbuf, &xattrbuf_min_size);
1716 * See what xattr are available.
1718 switch (xattr_list_len) {
1722 retval = bxattr_exit_ok;
1725 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1726 jcr->last_fname, be.bstrerror());
1727 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1728 jcr->last_fname, be.bstrerror());
1733 if (xattrbuf_min_size) {
1735 * The buffer isn't big enough to hold the xattr data, we now have
1736 * a minimum buffersize so we resize the buffer and try again.
1738 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1739 xattrbuf_size = xattrbuf_min_size + 1;
1740 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1741 xattrbuf, &xattrbuf_min_size);
1742 switch (xattr_list_len) {
1746 retval = bxattr_exit_ok;
1749 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1750 jcr->last_fname, be.bstrerror());
1751 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1752 jcr->last_fname, be.bstrerror());
1758 * This should never happen as we sized the buffer according to the minimumsize
1759 * returned by a previous getproplist call. If it does happen things are fishy and
1760 * we are better of forgetting this xattr as it seems its list is changing at this
1761 * exact moment so we can never make a good backup copy of it.
1763 retval = bxattr_exit_ok;
1772 retval = bxattr_exit_ok;
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", 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 if (xattr_value_list == NULL) {
1851 xattr_value_list = New(alist(10, not_owned_by_alist));
1854 xattr_value_list->append(current_xattr);
1855 current_xattr = NULL;
1860 * If we found any xattr send them to the SD.
1862 if (xattr_count > 0) {
1864 * Serialize the datastream.
1866 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1867 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1869 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1875 * Send the datastream to the SD.
1877 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1881 if (current_xattr != NULL) {
1882 if (current_xattr->value != NULL) {
1883 free(current_xattr->value);
1885 if (current_xattr->name != NULL) {
1886 free(current_xattr->name);
1888 free(current_xattr);
1890 if (xattr_value_list != NULL) {
1891 xattr_drop_internal_table(xattr_value_list);
1893 free_pool_memory(xattrbuf);
1898 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr, int stream)
1900 char *bp, *xattrbuf = NULL;
1901 int32_t xattrbuf_size, cnt;
1902 xattr_t *current_xattr;
1903 alist *xattr_value_list;
1904 bxattr_exit_code retval = bxattr_exit_error;
1907 xattr_value_list = New(alist(10, not_owned_by_alist));
1909 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1910 xattr_drop_internal_table(xattr_value_list);
1911 return bxattr_exit_error;
1915 * See how big the propertylist must be.
1918 foreach_alist(current_xattr, xattr_value_list) {
1919 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
1922 xattrbuf = (char *)malloc(xattrbuf_size);
1925 * Add all value pairs to the proplist.
1929 foreach_alist(current_xattr, xattr_value_list) {
1930 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
1931 current_xattr->value, &bp);
1937 if (cnt != xattrbuf_size) {
1938 Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
1940 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
1946 * Restore the list of extended attributes on the file.
1948 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
1953 retval = bxattr_exit_ok;
1956 Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
1957 jcr->last_fname, be.bstrerror());
1958 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
1959 jcr->last_fname, be.bstrerror());
1969 xattr_drop_internal_table(xattr_value_list);
1970 return bxattr_exit_ok;
1976 xattr_drop_internal_table(xattr_value_list);
1977 return bxattr_exit_error;
1981 * Function pointers to the build and parse function to use for these xattrs.
1983 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_xattr_streams;
1984 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = tru64_parse_xattr_streams;
1986 #elif defined(HAVE_SUN_OS)
1988 * Solaris extended attributes were introduced in Solaris 9
1991 * Solaris extensible attributes were introduced in OpenSolaris
1992 * by PSARC 2007/315 Solaris extensible attributes are also
1993 * sometimes called extended system attributes.
1995 * man fsattr(5) on Solaris gives a wealth of info. The most
1996 * important bits are:
1998 * Attributes are logically supported as files within the file
1999 * system. The file system is therefore augmented with an
2000 * orthogonal name space of file attributes. Any file (includ-
2001 * ing attribute files) can have an arbitrarily deep attribute
2002 * tree associated with it. Attribute values are accessed by
2003 * file descriptors obtained through a special attribute inter-
2004 * face. This logical view of "attributes as files" allows the
2005 * leveraging of existing file system interface functionality
2006 * to support the construction, deletion, and manipulation of
2009 * The special files "." and ".." retain their accustomed
2010 * semantics within the attribute hierarchy. The "." attribute
2011 * file refers to the current directory and the ".." attribute
2012 * file refers to the parent directory. The unnamed directory
2013 * at the head of each attribute tree is considered the "child"
2014 * of the file it is associated with and the ".." file refers
2015 * to the associated file. For any non-directory file with
2016 * attributes, the ".." entry in the unnamed directory refers
2017 * to a file that is not a directory.
2019 * Conceptually, the attribute model is fully general. Extended
2020 * attributes can be any type of file (doors, links, direc-
2021 * tories, and so forth) and can even have their own attributes
2022 * (fully recursive). As a result, the attributes associated
2023 * with a file could be an arbitrarily deep directory hierarchy
2024 * where each attribute could have an equally complex attribute
2025 * tree associated with it. Not all implementations are able
2026 * to, or want to, support the full model. Implementation are
2027 * therefore permitted to reject operations that are not sup-
2028 * ported. For example, the implementation for the UFS file
2029 * system allows only regular files as attributes (for example,
2030 * no sub-directories) and rejects attempts to place attributes
2033 * The following list details the operations that are rejected
2034 * in the current implementation:
2036 * link Any attempt to create links between
2037 * attribute and non-attribute space
2038 * is rejected to prevent security-
2039 * related or otherwise sensitive
2040 * attributes from being exposed, and
2041 * therefore manipulable, as regular
2044 * rename Any attempt to rename between
2045 * attribute and non-attribute space
2046 * is rejected to prevent an already
2047 * linked file from being renamed and
2048 * thereby circumventing the link res-
2051 * mkdir, symlink, mknod Any attempt to create a "non-
2052 * regular" file in attribute space is
2053 * rejected to reduce the functional-
2054 * ity, and therefore exposure and
2055 * risk, of the initial implementa-
2058 * The entire available name space has been allocated to "gen-
2059 * eral use" to bring the implementation in line with the NFSv4
2060 * draft standard [NFSv4]. That standard defines "named attri-
2061 * butes" (equivalent to Solaris Extended Attributes) with no
2062 * naming restrictions. All Sun applications making use of
2063 * opaque extended attributes will use the prefix "SUNW".
2066 #ifdef HAVE_SYS_ATTR_H
2067 #include <sys/attr.h>
2074 #ifdef HAVE_SYS_NVPAIR_H
2075 #include <sys/nvpair.h>
2078 #ifdef HAVE_SYS_ACL_H
2079 #include <sys/acl.h>
2082 #if !defined(HAVE_OPENAT) || \
2083 !defined(HAVE_UNLINKAT) || \
2084 !defined(HAVE_FCHOWNAT) || \
2085 !defined(HAVE_FUTIMESAT)
2086 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2090 * Define the supported XATTR streams for this OS
2092 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2093 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
2095 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
2096 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2099 * This code creates a temporary cache with entries for each xattr which has
2100 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2102 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2104 xattr_link_cache_entry_t *ptr;
2106 foreach_alist(ptr, jcr->xattr_data->link_cache) {
2107 if (ptr && ptr->inum == inum) {
2114 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2116 xattr_link_cache_entry_t *ptr;
2118 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2119 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
2121 bstrncpy(ptr->target, target, sizeof(ptr->target));
2122 jcr->xattr_data->link_cache->append(ptr);
2125 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2127 * This function returns true if a non default extended system attribute
2128 * list is associated with fd and returns false when an error has occured
2129 * or when only extended system attributes other than archive,
2130 * av_modified or crtime are set.
2132 * The function returns true for the following cases:
2134 * - any extended system attribute other than the default attributes
2135 * ('archive', 'av_modified' and 'crtime') is set
2136 * - nvlist has NULL name string
2137 * - nvpair has data type of 'nvlist'
2138 * - default data type.
2140 static bool solaris_has_non_transient_extensible_attributes(int fd)
2148 bool retval = false;
2150 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2155 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2156 name = nvpair_name(pair);
2159 fattr = name_to_attr(name);
2165 type = nvpair_type(pair);
2167 case DATA_TYPE_BOOLEAN_VALUE:
2168 if (nvpair_value_boolean_value(pair, &value) != 0) {
2171 if (value && fattr != F_ARCHIVE &&
2172 fattr != F_AV_MODIFIED) {
2177 case DATA_TYPE_UINT64_ARRAY:
2178 if (fattr != F_CRTIME) {
2183 case DATA_TYPE_NVLIST:
2191 if (response != NULL) {
2192 nvlist_free(response);
2196 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2198 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2200 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2201 * There is no need to store those acls as we already store the stat bits too.
2203 static bool acl_is_trivial(int count, aclent_t *entries)
2208 for (n = 0; n < count; n++) {
2210 if (!(ace->a_type == USER_OBJ ||
2211 ace->a_type == GROUP_OBJ ||
2212 ace->a_type == OTHER_OBJ ||
2213 ace->a_type == CLASS_OBJ))
2218 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2220 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2223 #ifdef HAVE_EXTENDED_ACL
2229 * See if this attribute has an ACL
2231 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2232 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2234 * See if there is a non trivial acl on the file.
2236 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2237 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2240 return bxattr_exit_ok;
2242 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2243 attrname, jcr->last_fname, be.bstrerror());
2244 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2245 attrname, jcr->last_fname, be.bstrerror());
2246 return bxattr_exit_error;
2251 #if defined(ACL_SID_FMT)
2253 * New format flag added in newer Solaris versions.
2255 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2257 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2258 #endif /* ACL_SID_FMT */
2260 *acl_text = acl_totext(aclp, flags);
2268 return bxattr_exit_ok;
2269 #else /* HAVE_EXTENDED_ACL */
2271 aclent_t *acls = NULL;
2275 * See if this attribute has an ACL
2278 n = facl(fd, GETACLCNT, 0, NULL);
2280 n = acl(attrname, GETACLCNT, 0, NULL);
2283 if (n >= MIN_ACL_ENTRIES) {
2284 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2285 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2286 acl(attrname, GETACL, n, acls) != n) {
2290 return bxattr_exit_ok;
2292 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2293 attrname, jcr->last_fname, be.bstrerror());
2294 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2295 attrname, jcr->last_fname, be.bstrerror());
2297 return bxattr_exit_error;
2302 * See if there is a non trivial acl on the file.
2304 if (!acl_is_trivial(n, acls)) {
2305 if ((*acl_text = acltotext(acls, n)) == NULL) {
2306 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2307 attrname, jcr->last_fname, be.bstrerror());
2308 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2309 attrname, jcr->last_fname, be.bstrerror());
2311 return bxattr_exit_error;
2321 return bxattr_exit_ok;
2322 #endif /* HAVE_EXTENDED_ACL */
2324 #else /* HAVE_ACL */
2325 return bxattr_exit_ok;
2326 #endif /* HAVE_ACL */
2330 * Forward declaration for recursive function call.
2332 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2335 * Save an extended or extensible attribute.
2336 * This is stored as an opaque stream of bytes with the following encoding:
2338 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2340 * or for a hardlinked or symlinked attribute
2342 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2344 * xattr_name can be a subpath relative to the file the xattr is on.
2345 * stat_buffer is the string representation of the stat struct.
2346 * acl_string is an acl text when a non trivial acl is set on the xattr.
2347 * actual_xattr_data is the content of the xattr file.
2349 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2350 const char *attrname, bool toplevel_hidden_dir, int stream)
2355 xattr_link_cache_entry_t *xlce;
2356 char target_attrname[PATH_MAX];
2357 char link_source[PATH_MAX];
2358 char *acl_text = NULL;
2359 char attribs[MAXSTRING];
2360 char buffer[XATTR_BUFSIZ];
2361 bxattr_exit_code retval = bxattr_exit_error;
2364 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2367 * Get the stats of the extended or extensible attribute.
2369 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2372 retval = bxattr_exit_ok;
2375 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2376 target_attrname, jcr->last_fname, be.bstrerror());
2377 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2378 target_attrname, jcr->last_fname, be.bstrerror());
2384 * Based on the filetype perform the correct action. We support most filetypes here, more
2385 * then the actual implementation on Solaris supports so some code may never get executed
2386 * due to limitations in the implementation.
2388 switch (st.st_mode & S_IFMT) {
2393 * Get any acl on the xattr.
2395 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2399 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2400 * Encode the stat struct into an ASCII representation.
2402 encode_stat(attribs, &st, sizeof(st), 0, stream);
2403 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2404 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2408 * Get any acl on the xattr.
2410 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2414 * See if this is the toplevel_hidden_dir being saved.
2416 if (toplevel_hidden_dir) {
2418 * Save the data for later storage when we encounter a real xattr. We store the data
2419 * in the jcr->xattr_data->content buffer and flush that just before sending out the
2420 * first real xattr. Encode the stat struct into an ASCII representation and jump
2421 * out of the function.
2423 encode_stat(attribs, &st, sizeof(st), 0, stream);
2424 cnt = bsnprintf(buffer, sizeof(buffer),
2426 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2427 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2428 jcr->xattr_data->content_length = cnt;
2432 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2433 * Encode the stat struct into an ASCII representation.
2435 encode_stat(attribs, &st, sizeof(st), 0, stream);
2436 cnt = bsnprintf(buffer, sizeof(buffer),
2438 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2443 * If this is a hardlinked file check the inode cache for a hit.
2445 if (st.st_nlink > 1) {
2447 * See if the cache already knows this inode number.
2449 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2451 * Generate a xattr encoding with the reference to the target in there.
2453 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2454 cnt = bsnprintf(buffer, sizeof(buffer),
2456 target_attrname, 0, attribs, 0, xlce->target, 0);
2457 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2458 jcr->xattr_data->content_length = cnt;
2459 retval = send_xattr_stream(jcr, stream);
2462 * For a hard linked file we are ready now, no need to recursively save the attributes.
2468 * Store this hard linked file in the cache.
2469 * Store the name relative to the top level xattr space.
2471 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2475 * Get any acl on the xattr.
2477 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2482 * Encode the stat struct into an ASCII representation.
2484 encode_stat(attribs, &st, sizeof(st), 0, stream);
2485 cnt = bsnprintf(buffer, sizeof(buffer),
2487 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2490 * Open the extended or extensible attribute file.
2492 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2495 retval = bxattr_exit_ok;
2498 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2499 target_attrname, jcr->last_fname, be.bstrerror());
2500 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2501 target_attrname, jcr->last_fname, be.bstrerror());
2508 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2509 * Encode the stat struct into an ASCII representation.
2511 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2514 retval = bxattr_exit_ok;
2517 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2518 target_attrname, jcr->last_fname, be.bstrerror());
2519 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2520 target_attrname, jcr->last_fname, be.bstrerror());
2526 * Generate a xattr encoding with the reference to the target in there.
2528 encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
2529 cnt = bsnprintf(buffer, sizeof(buffer),
2531 target_attrname, 0, attribs, 0, link_source, 0);
2532 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2533 jcr->xattr_data->content_length = cnt;
2534 retval = send_xattr_stream(jcr, stream);
2536 if (retval == bxattr_exit_ok) {
2537 jcr->xattr_data->nr_saved++;
2541 * For a soft linked file we are ready now, no need to recursively save the attributes.
2549 * See if this is the first real xattr being saved.
2550 * If it is save the toplevel_hidden_dir attributes first.
2551 * This is easy as its stored already in the jcr->xattr_data->content buffer.
2553 if (jcr->xattr_data->nr_saved == 0) {
2554 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2555 if (retval != bxattr_exit_ok) {
2558 jcr->xattr_data->nr_saved++;
2561 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2562 jcr->xattr_data->content_length = cnt;
2565 * Only dump the content of regular files.
2567 switch (st.st_mode & S_IFMT) {
2569 if (st.st_size > 0) {
2571 * Protect ourself against things getting out of hand.
2573 if (st.st_size >= MAX_XATTR_STREAM) {
2574 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2575 jcr->last_fname, MAX_XATTR_STREAM);
2579 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2580 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
2581 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
2582 jcr->xattr_data->content_length += cnt;
2586 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
2587 target_attrname, jcr->last_fname);
2588 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2589 target_attrname, jcr->last_fname);
2600 retval = send_xattr_stream(jcr, stream);
2601 if (retval == bxattr_exit_ok) {
2602 jcr->xattr_data->nr_saved++;
2607 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2608 * available on this extended attribute.
2611 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2614 * The recursive call could change our working dir so change back to the wanted workdir.
2616 if (fchdir(fd) < 0) {
2619 retval = bxattr_exit_ok;
2622 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2623 jcr->last_fname, be.bstrerror());
2624 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2625 jcr->last_fname, fd, be.bstrerror());
2632 if (acl_text != NULL) {
2641 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2644 int fd, filefd = -1, attrdirfd = -1;
2647 char current_xattr_namespace[PATH_MAX];
2648 bxattr_exit_code retval = bxattr_exit_error;
2652 * Determine what argument to use. Use attr_parent when set
2653 * (recursive call) or jcr->last_fname for first call. Also save
2654 * the current depth of the xattr_space we are in.
2658 if (xattr_namespace) {
2659 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2660 xattr_namespace, attr_parent);
2662 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2665 name = jcr->last_fname;
2666 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2670 * Open the file on which to save the xattrs read-only.
2672 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2675 retval = bxattr_exit_ok;
2678 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2679 jcr->last_fname, be.bstrerror());
2680 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2681 jcr->last_fname, be.bstrerror());
2687 * Open the xattr naming space.
2689 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2693 * Gentile way of the system saying this type of xattr layering is not supported.
2694 * Which is not problem we just forget about this this xattr.
2695 * But as this is not an error we return a positive return value.
2697 retval = bxattr_exit_ok;
2700 retval = bxattr_exit_ok;
2703 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2704 name, jcr->last_fname, be.bstrerror());
2705 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2706 name, jcr->last_fname, be.bstrerror());
2712 * We need to change into the attribute directory to determine if each of the
2713 * attributes should be saved.
2715 if (fchdir(attrdirfd) < 0) {
2716 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2717 jcr->last_fname, be.bstrerror());
2718 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2719 jcr->last_fname, attrdirfd, be.bstrerror());
2724 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2725 * else because the readdir returns "." entry after the extensible attr entry.
2726 * And as we want this entry before anything else we better just save its data.
2729 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2730 true, STREAM_XATTR_SOLARIS);
2732 if ((fd = dup(attrdirfd)) == -1 ||
2733 (dirp = fdopendir(fd)) == (DIR *)NULL) {
2734 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2735 jcr->last_fname, be.bstrerror());
2736 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
2737 jcr->last_fname, fd, be.bstrerror());
2743 * Walk the namespace.
2745 while ((dp = readdir(dirp)) != NULL) {
2747 * Skip only the toplevel . dir.
2749 if (!attr_parent && bstrcmp(dp->d_name, "."))
2753 * Skip all .. directories
2755 if (bstrcmp(dp->d_name, ".."))
2758 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2759 current_xattr_namespace, dp->d_name, jcr->last_fname);
2761 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2763 * We are not interested in read-only extensible attributes.
2765 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2766 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2767 current_xattr_namespace, dp->d_name, jcr->last_fname);
2773 * We are only interested in read-write extensible attributes
2774 * when they contain non-transient values.
2776 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2778 * Determine if there are non-transient system attributes at the toplevel.
2779 * We need to provide a fd to the open file.
2781 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2782 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2783 current_xattr_namespace, dp->d_name, jcr->last_fname);
2790 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2791 false, STREAM_XATTR_SOLARIS_SYS);
2794 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2799 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2800 false, STREAM_XATTR_SOLARIS);
2804 retval = bxattr_exit_ok;
2807 if (attrdirfd != -1)
2815 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
2817 #ifdef HAVE_EXTENDED_ACL
2822 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
2823 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
2825 return bxattr_exit_error;
2828 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
2829 acl_set(attrname, aclp) != 0) {
2830 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2831 attrname, jcr->last_fname, be.bstrerror());
2832 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2833 attrname, jcr->last_fname, be.bstrerror());
2834 return bxattr_exit_error;
2840 return bxattr_exit_ok;
2842 #else /* HAVE_EXTENDED_ACL */
2844 aclent_t *acls = NULL;
2847 acls = aclfromtext(acl_text, &n);
2849 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
2850 acl(attrname, SETACL, n, acls) != 0) {
2851 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2852 attrname, jcr->last_fname, be.bstrerror());
2853 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2854 attrname, jcr->last_fname, be.bstrerror());
2855 return bxattr_exit_error;
2862 return bxattr_exit_ok;
2864 #endif /* HAVE_EXTENDED_ACL */
2867 #endif /* HAVE_ACL */
2869 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
2871 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
2872 int used_bytes, total_bytes, cnt;
2873 char *bp, *target_attrname, *attribs;
2874 char *linked_target = NULL;
2875 char *acl_text = NULL;
2879 struct timeval times[2];
2880 bxattr_exit_code retval = bxattr_exit_error;
2884 * Parse the xattr stream. First the part that is the same for all xattrs.
2887 total_bytes = jcr->xattr_data->content_length;
2890 * The name of the target xattr has a leading / we are not interested
2891 * in that so skip it when decoding the string. We always start a the /
2892 * of the xattr space anyway.
2894 target_attrname = jcr->xattr_data->content + 1;
2895 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
2896 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2902 * Open the file on which to restore the xattrs read-only.
2904 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
2905 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2906 jcr->last_fname, be.bstrerror());
2907 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2908 jcr->last_fname, be.bstrerror());
2913 * Open the xattr naming space and make it the current working dir.
2915 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2916 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
2917 jcr->last_fname, be.bstrerror());
2918 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
2919 jcr->last_fname, be.bstrerror());
2923 if (fchdir(attrdirfd) < 0) {
2924 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2925 jcr->last_fname, be.bstrerror());
2926 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2927 jcr->last_fname, attrdirfd, be.bstrerror());
2932 * Try to open the correct xattr subdir based on the target_attrname given.
2933 * e.g. check if its a subdir attrname. Each / in the string makes us go
2936 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2939 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2940 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2941 target_attrname, jcr->last_fname, be.bstrerror());
2942 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2943 target_attrname, jcr->last_fname, be.bstrerror());
2951 * Open the xattr naming space.
2953 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2954 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2955 target_attrname, jcr->last_fname, be.bstrerror());
2956 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2957 target_attrname, jcr->last_fname, be.bstrerror());
2965 * Make the xattr space our current workingdir.
2967 if (fchdir(attrdirfd) < 0) {
2968 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2969 target_attrname, jcr->last_fname, be.bstrerror());
2970 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2971 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2975 target_attrname = ++bp;
2979 * Decode the attributes from the stream.
2981 decode_stat(attribs, &st, sizeof(st), &inum);
2984 * Decode the next field (acl_text).
2986 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2987 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2993 * Based on the filetype perform the correct action. We support most filetypes here, more
2994 * then the actual implementation on Solaris supports so some code may never get executed
2995 * due to limitations in the implementation.
2997 switch (st.st_mode & S_IFMT) {
3000 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3002 unlinkat(attrdirfd, target_attrname, 0);
3003 if (mkfifo(target_attrname, st.st_mode) < 0) {
3004 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
3005 target_attrname, jcr->last_fname, be.bstrerror());
3006 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
3007 target_attrname, jcr->last_fname, be.bstrerror());
3014 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3016 unlinkat(attrdirfd, target_attrname, 0);
3017 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3018 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3019 target_attrname, jcr->last_fname, be.bstrerror());
3020 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3021 target_attrname, jcr->last_fname, be.bstrerror());
3027 * If its not the hidden_dir create the entry.
3028 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3030 if (!bstrcmp(target_attrname, ".")) {
3031 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3032 if (mkdir(target_attrname, st.st_mode) < 0) {
3033 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3034 target_attrname, jcr->last_fname, be.bstrerror());
3035 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3036 target_attrname, jcr->last_fname, be.bstrerror());
3043 * See if this is a hard linked file. e.g. inum != 0
3048 unlinkat(attrdirfd, target_attrname, 0);
3049 if (link(linked_target, target_attrname) < 0) {
3050 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3051 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3052 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3053 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3058 * Successfully restored xattr.
3060 retval = bxattr_exit_ok;
3063 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3064 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
3068 if (used_bytes < (total_bytes - 1))
3072 * Restore the actual xattr.
3074 if (!is_extensible) {
3075 unlinkat(attrdirfd, target_attrname, 0);
3078 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3079 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3080 target_attrname, jcr->last_fname, be.bstrerror());
3081 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3082 target_attrname, jcr->last_fname, be.bstrerror());
3088 * Restore the actual data.
3090 if (st.st_size > 0) {
3091 used_bytes = (data - jcr->xattr_data->content);
3092 cnt = total_bytes - used_bytes;
3095 * Do a sanity check, the st.st_size should be the same as the number of bytes
3096 * we have available as data of the stream.
3098 if (cnt != st.st_size) {
3099 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3100 target_attrname, jcr->last_fname);
3101 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3102 target_attrname, jcr->last_fname);
3107 cnt = write(attrfd, data, cnt);
3109 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3110 target_attrname, jcr->last_fname, be.bstrerror());
3111 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3112 target_attrname, jcr->last_fname, be.bstrerror());
3118 cnt = total_bytes - used_bytes;
3124 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3128 if (symlink(linked_target, target_attrname) < 0) {
3129 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3130 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3131 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3132 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3137 * Successfully restored xattr.
3139 retval = bxattr_exit_ok;
3146 * Restore owner and acl for non extensible attributes.
3148 if (!is_extensible) {
3149 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3153 * Gentile way of the system saying this type of xattr layering is not supported.
3154 * But as this is not an error we return a positive return value.
3156 retval = bxattr_exit_ok;
3159 retval = bxattr_exit_ok;
3162 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3163 target_attrname, jcr->last_fname, be.bstrerror());
3164 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3165 target_attrname, jcr->last_fname, be.bstrerror());
3172 if (acl_text && *acl_text)
3173 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3175 #endif /* HAVE_ACL */
3178 * For a non extensible attribute restore access and modification time on the xattr.
3180 if (!is_extensible) {
3181 times[0].tv_sec = st.st_atime;
3182 times[0].tv_usec = 0;
3183 times[1].tv_sec = st.st_mtime;
3184 times[1].tv_usec = 0;
3186 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3187 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3188 target_attrname, jcr->last_fname, be.bstrerror());
3189 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3190 target_attrname, jcr->last_fname, be.bstrerror());
3196 * Successfully restored xattr.
3198 retval = bxattr_exit_ok;
3202 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3204 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3211 if (attrdirfd != -1) {
3220 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3223 bxattr_exit_code retval = bxattr_exit_ok;
3226 * First see if extended attributes or extensible attributes are present.
3227 * If not just pretend things went ok.
3229 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3230 jcr->xattr_data->nr_saved = 0;
3231 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
3234 * As we change the cwd in the save function save the current cwd
3235 * for restore after return from the solaris_save_xattrs function.
3237 getcwd(cwd, sizeof(cwd));
3238 retval = solaris_save_xattrs(jcr, NULL, NULL);
3240 delete jcr->xattr_data->link_cache;
3241 jcr->xattr_data->link_cache = NULL;
3246 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
3249 bool is_extensible = false;
3250 bxattr_exit_code retval;
3253 * First make sure we can restore xattr on the filesystem.
3256 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3257 case STREAM_XATTR_SOLARIS_SYS:
3258 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3259 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
3260 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3262 return bxattr_exit_error;
3265 is_extensible = true;
3268 case STREAM_XATTR_SOLARIS:
3269 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3270 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
3271 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3273 return bxattr_exit_error;
3277 return bxattr_exit_error;
3281 * As we change the cwd in the restore function save the current cwd
3282 * for restore after return from the solaris_restore_xattrs function.
3284 getcwd(cwd, sizeof(cwd));
3285 retval = solaris_restore_xattrs(jcr, is_extensible);
3292 * Function pointers to the build and parse function to use for these xattrs.
3294 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
3295 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
3297 #endif /* defined(HAVE_SUN_OS) */
3300 * Entry points when compiled with support for XATTRs on a supported platform.
3302 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3304 if (os_build_xattr_streams) {
3305 return (*os_build_xattr_streams)(jcr, ff_pkt);
3307 return bxattr_exit_error;
3310 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
3314 if (os_parse_xattr_streams) {
3316 * See if we can parse this stream, and ifso give it a try.
3318 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3319 if (os_default_xattr_streams[cnt] == stream) {
3320 return (*os_parse_xattr_streams)(jcr, stream);
3325 * Issue a warning and discard the message. But pretend the restore was ok.
3327 Jmsg2(jcr, M_WARNING, 0,
3328 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3329 jcr->last_fname, stream);
3330 return bxattr_exit_error;