2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2010 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Functions to handle Extended Attributes for bacula.
31 * Extended Attributes are so OS specific we only restore Extended Attributes if
32 * they were saved using a filed on the same platform.
34 * Currently we support the following OSes:
35 * - AIX (Extended Attributes)
36 * - Darwin (Extended Attributes)
37 * - IRIX (Extended Attributes)
38 * - Linux (Extended Attributes)
39 * - NetBSD (Extended Attributes)
40 * - FreeBSD (Extended Attributes)
41 * - OpenBSD (Extended Attributes)
42 * (As it seems either they never implemented xattr or they are removed
43 * the support as it stated it was in version 3.1 but the current syscall
44 * tabled shows the extattr_ functions are not implemented. So as such we
45 * might eventually support xattr on OpenBSD when they implemented them using
46 * the same interface as FreeBSD and NetBSD.
47 * - Solaris (Extended Attributes and Extensible Attributes)
49 * Written by Marco van Wieringen, November MMVIII
56 #if !defined(HAVE_XATTR)
58 * Entry points when compiled without support for XATTRs or on an unsupported platform.
60 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
62 return bxattr_exit_fatal;
65 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
67 return bxattr_exit_fatal;
71 * Send a XATTR stream to the SD.
73 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
75 BSOCK *sd = jcr->store_bsock;
77 #ifdef FD_NO_SEND_TEST
78 return bxattr_exit_ok;
84 if (jcr->xattr_data->content_length <= 0) {
85 return bxattr_exit_ok;
91 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
92 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
94 return bxattr_exit_fatal;
98 * Send the buffer to the storage deamon
100 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
102 sd->msg = jcr->xattr_data->content;
103 sd->msglen = jcr->xattr_data->content_length;
107 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
109 return bxattr_exit_fatal;
112 jcr->JobBytes += sd->msglen;
114 if (!sd->signal(BNET_EOD)) {
115 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
117 return bxattr_exit_fatal;
119 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
120 return bxattr_exit_ok;
124 * First some generic functions for OSes that use the same xattr encoding scheme.
125 * Currently for all OSes except for Solaris.
127 #if !defined(HAVE_SUN_OS)
128 static void xattr_drop_internal_table(alist *xattr_value_list)
130 xattr_t *current_xattr;
133 * Walk the list of xattrs and free allocated memory on traversing.
135 foreach_alist(current_xattr, xattr_value_list) {
137 * See if we can shortcut.
139 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
142 free(current_xattr->name);
144 if (current_xattr->value_length > 0)
145 free(current_xattr->value);
150 delete xattr_value_list;
154 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
155 * which encodes one or more xattr_t structures.
157 * The Serialized stream consists of the following elements:
158 * magic - A magic string which makes it easy to detect any binary incompatabilites
159 * name_length - The length of the following xattr name
160 * name - The name of the extended attribute
161 * value_length - The length of the following xattr data
162 * value - The actual content of the extended attribute
164 * This is repeated 1 or more times.
167 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, alist *xattr_value_list)
169 xattr_t *current_xattr;
173 * Make sure the serialized stream fits in the poolmem buffer.
174 * We allocate some more to be sure the stream is gonna fit.
176 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
177 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
180 * Walk the list of xattrs and serialize the data.
182 foreach_alist(current_xattr, xattr_value_list) {
184 * See if we can shortcut.
186 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
189 ser_uint32(current_xattr->magic);
190 ser_uint32(current_xattr->name_length);
191 ser_bytes(current_xattr->name, current_xattr->name_length);
193 ser_uint32(current_xattr->value_length);
194 if (current_xattr->value_length > 0 && current_xattr->value) {
195 ser_bytes(current_xattr->value, current_xattr->value_length);
197 Dmsg3(100, "Backup xattr named %s, value %*s\n",
198 current_xattr->name, current_xattr->value, current_xattr->value);
200 Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
204 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
205 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
207 return jcr->xattr_data->content_length;
210 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
213 xattr_t *current_xattr;
214 bxattr_exit_code retval = bxattr_exit_ok;
217 * Parse the stream and call restore_xattr_on_file for each extended attribute.
219 * Start unserializing the data. We keep on looping while we have not
220 * unserialized all bytes in the stream.
222 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
223 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
225 * First make sure the magic is present. This way we can easily catch corruption.
226 * Any missing MAGIC is fatal we do NOT try to continue.
229 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
230 unser_uint32(current_xattr->magic);
231 if (current_xattr->magic != XATTR_MAGIC) {
232 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
234 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
237 return bxattr_exit_error;
241 * Decode the valuepair. First decode the length of the name.
243 unser_uint32(current_xattr->name_length);
244 if (current_xattr->name_length == 0) {
245 Mmsg1(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
247 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
250 return bxattr_exit_error;
254 * Allocate room for the name and decode its content.
256 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
257 unser_bytes(current_xattr->name, current_xattr->name_length);
260 * The xattr_name needs to be null terminated.
262 current_xattr->name[current_xattr->name_length] = '\0';
265 * Decode the value length.
267 unser_uint32(current_xattr->value_length);
269 if (current_xattr->value_length > 0) {
271 * Allocate room for the value and decode its content.
273 current_xattr->value = (char *)malloc(current_xattr->value_length);
274 unser_bytes(current_xattr->value, current_xattr->value_length);
276 Dmsg3(100, "Restoring xattr named %s, value %*s\n",
277 current_xattr->name, current_xattr->value, current_xattr->value);
279 current_xattr->value = NULL;
280 Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
283 xattr_value_list->append(current_xattr);
286 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
292 * This is a supported OS, See what kind of interface we should use.
294 #if defined(HAVE_AIX_OS)
296 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
297 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
298 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
299 #error "Missing full support for the Extended Attributes (EA) functions."
305 #error "Missing sys/ea.h header file"
309 * Define the supported XATTR streams for this OS
311 static int os_default_xattr_streams[1] = { STREAM_XATTR_AIX };
314 * Fallback to the non l-functions when those are not available.
316 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
319 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
322 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
323 #define llistea listea
326 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
329 char *xattr_list, *bp;
330 int cnt, xattr_count = 0;
331 uint32_t name_length;
332 int32_t xattr_list_len,
334 uint32_t expected_serialize_len = 0;
335 xattr_t *current_xattr;
336 alist *xattr_value_list = NULL;
337 bxattr_exit_code retval = bxattr_exit_error;
341 * First get the length of the available list with extended attributes.
343 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
344 switch (xattr_list_len) {
350 return bxattr_exit_ok;
352 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
353 jcr->last_fname, be.bstrerror());
354 Dmsg2(100, "llistea error file=%s ERR=%s\n",
355 jcr->last_fname, be.bstrerror());
356 return bxattr_exit_error;
360 return bxattr_exit_ok;
366 * Allocate room for the extented attribute list.
368 xattr_list = (char *)malloc(xattr_list_len + 1);
369 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
372 * Get the actual list of extended attributes names for a file.
374 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
375 switch (xattr_list_len) {
381 retval = bxattr_exit_ok;
384 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
385 jcr->last_fname, be.bstrerror());
386 Dmsg2(100, "llistea error file=%s ERR=%s\n",
387 jcr->last_fname, be.bstrerror());
394 xattr_list[xattr_list_len] = '\0';
396 xattr_value_list = New(alist(10, not_owned_by_alist));
399 * Walk the list of extended attributes names and retrieve the data.
400 * We already count the bytes needed for serializing the stream later on.
403 while ((bp - xattr_list) + 1 < xattr_list_len) {
407 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
413 name_length = strlen(bp);
414 if (skip_xattr || name_length == 0) {
415 bp = strchr(bp, '\0') + 1;
416 Dmsg1(100, "Skipping xattr named %s\n", current_xattr->name);
421 * Each xattr valuepair starts with a magic so we can parse it easier.
423 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
424 current_xattr->magic = XATTR_MAGIC;
425 expected_serialize_len += sizeof(current_xattr->magic);
428 * Allocate space for storing the name.
430 current_xattr->name_length = name_length;
431 current_xattr->name = (char *)malloc(current_xattr->name_length);
432 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
434 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
437 * First see how long the value is for the extended attribute.
439 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
440 switch (xattr_value_len) {
446 retval = bxattr_exit_ok;
447 free(current_xattr->name);
451 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
452 jcr->last_fname, be.bstrerror());
453 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
454 jcr->last_fname, be.bstrerror());
455 free(current_xattr->name);
461 current_xattr->value = NULL;
462 current_xattr->value_length = 0;
463 expected_serialize_len += sizeof(current_xattr->value_length);
467 * Allocate space for storing the value.
469 current_xattr->value = (char *)malloc(xattr_value_len);
470 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
472 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
473 if (xattr_value_len < 0) {
478 retval = bxattr_exit_ok;
479 free(current_xattr->value);
480 free(current_xattr->name);
484 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
485 jcr->last_fname, be.bstrerror());
486 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
487 jcr->last_fname, be.bstrerror());
488 free(current_xattr->value);
489 free(current_xattr->name);
495 * Store the actual length of the value.
497 current_xattr->value_length = xattr_value_len;
498 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
501 * Protect ourself against things getting out of hand.
503 if (expected_serialize_len >= MAX_XATTR_STREAM) {
504 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
505 jcr->last_fname, MAX_XATTR_STREAM);
506 free(current_xattr->value);
507 free(current_xattr->name);
513 xattr_value_list->append(current_xattr);
515 bp = strchr(bp, '\0') + 1;
520 xattr_list = (char *)NULL;
523 * If we found any xattr send them to the SD.
525 if (xattr_count > 0) {
527 * Serialize the datastream.
529 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
530 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
532 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
537 xattr_drop_internal_table(xattr_value_list);
540 * Send the datastream to the SD.
542 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
544 xattr_drop_internal_table(xattr_value_list);
546 return bxattr_exit_ok;
550 if (xattr_list != NULL) {
553 if (xattr_value_list != NULL) {
554 xattr_drop_internal_table(xattr_value_list);
559 static bxattr_exit_code aix_xattr_parse_streams(JCR *jcr, int stream)
561 xattr_t *current_xattr;
562 alist *xattr_value_list;
565 xattr_value_list = New(alist(10, not_owned_by_alist));
567 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
568 xattr_drop_internal_table(xattr_value_list);
569 return bxattr_exit_error;
572 foreach_alist(current_xattr, xattr_value_list) {
573 if (lsetea(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
580 Mmsg2(jcr->errmsg, _("lsetea error on file \"%s\": ERR=%s\n"),
581 jcr->last_fname, be.bstrerror());
582 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
583 jcr->last_fname, be.bstrerror());
589 xattr_drop_internal_table(xattr_value_list);
590 return bxattr_exit_ok;
593 xattr_drop_internal_table(xattr_value_list);
594 return bxattr_exit_error;
598 * Function pointers to the build and parse function to use for these xattrs.
600 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_xattr_build_streams;
601 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = aix_xattr_parse_streams;
603 #elif defined(HAVE_IRIX_OS)
606 * Define the supported XATTR streams for this OS
608 static int os_default_xattr_streams[1] = { STREAM_XATTR_IRIX };
609 static const char *xattr_acl_skiplist[1] = { NULL };
610 static const char *xattr_skiplist[1] = { NULL };
612 struct xattr_naming_space {
617 static xattr_naming_space xattr_naming_spaces[] = {
618 { "user.", ATTR_DONTFOLLOW },
619 { "root.", ATTR_ROOT | ATTR_DONTFOLLOW },
623 static bxattr_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
625 int cnt, xattr_count = 0;
626 POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
627 bxattr_exit_code retval = bxattr_exit_error;
628 attrlist_cursor_t cursor;
629 attrlist_t *attrlist;
630 attrlist_ent_t *attrlist_ent;
631 alist *xattr_value_list = NULL;
634 xattr_value_list = New(alist(10, not_owned_by_alist));
636 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
637 memset(cursor, 0, sizeof(attrlist_cursor_t));
639 if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
640 xattr_naming_spaces[cnt].flags, &cursor) != 0) {
643 retval = bxattr_exit_ok;
646 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
647 jcr->last_fname, be.bstrerror());
648 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
649 jcr->last_fname, be.bstrerror());
654 attrlist = (attrlist_t *)xattrbuf;
657 * Walk the available attributes.
659 for (cnt = 0; cnt < attrlist->al_count; cnt++) {
660 attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
663 * Each xattr valuepair starts with a magic so we can parse it easier.
665 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
666 current_xattr->magic = XATTR_MAGIC;
667 expected_serialize_len += sizeof(current_xattr->magic);
670 * Allocate space for storing the name.
671 * We store the name as <naming_space_name><xattr_name>
673 current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) + strlen(attrlist_ent->a_name) + 2;
674 current_xattr->name = (char *)malloc(current_xattr->name_length);
675 bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
676 xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
678 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
680 current_xattr->value_length = attrlist_ent->a_valuelen;
681 current_xattr->value = (char *)malloc(current_xattr->value_length);
682 memset((caddr_t)current_xattr->value, 0, current_xattr->value_length);
685 * Retrieve the actual value of the xattr.
687 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
688 current_xattr->value_length, xattr_naming_spaces[cnt].flags) != 0) {
692 free(current_xattr->value);
693 free(current_xattr->name);
695 retval = bxattr_exit_ok;
700 free(current_xattr->value);
701 free(current_xattr->name);
703 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
704 jcr->last_fname, be.bstrerror());
705 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
706 jcr->last_fname, be.bstrerror());
711 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
714 * Protect ourself against things getting out of hand.
716 if (expected_serialize_len >= MAX_XATTR_STREAM) {
717 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
718 jcr->last_fname, MAX_XATTR_STREAM);
722 xattr_value_list->append(current_xattr);
727 * See if there are more attributes available for a next run of attr_list.
729 if (attrlist->al_more == 0) {
736 * If we found any xattr send them to the SD.
738 if (xattr_count > 0) {
740 * Serialize the datastream.
742 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
743 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
745 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
750 xattr_drop_internal_table(xattr_value_list);
753 * Send the datastream to the SD.
755 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
757 xattr_drop_internal_table(xattr_value_list);
759 return bxattr_exit_ok;
763 free_pool_memory(xattrbuf);
765 if (xattr_value_list != NULL) {
766 xattr_drop_internal_table(xattr_value_list);
771 static bxattr_exit_code irix_xattr_parse_streams(JCR *jcr, int stream)
774 xattr_t *current_xattr;
775 alist *xattr_value_list;
776 xattr_naming_space *xattr_naming_space;
779 xattr_value_list = New(alist(10, not_owned_by_alist));
781 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
782 xattr_drop_internal_table(xattr_value_list);
783 return bxattr_exit_error;
786 foreach_alist(current_xattr, xattr_value_list) {
788 * See to what namingspace this xattr belongs to.
790 xattr_naming_space = NULL;
791 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
792 cmp_size = strlen(xattr_naming_spaces[cnt].name);
793 if (!strncasecmp(current_xattr->name,
794 xattr_naming_spaces[cnt].name,
796 xattr_naming_space = &xattr_naming_spaces[cnt];
802 * If we got a xattr that doesn't belong to ant valid namespace complain.
804 if (xattr_naming_space == NULL) {
805 Mmsg2(jcr->errmsg, _("Received illegal xattr named %s on file \"%s\"\n"),
806 current_xattr->name, jcr->last_fname);
807 Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
808 current_xattr->name, jcr->last_fname);
813 * Restore the xattr first try to create the attribute from scratch.
815 flags = xattr_naming_space->flags | ATTR_CREATE;
816 if (attr_set(jcr->last_fname, current_xattr->name,
817 current_xattr->value, current_xattr->value_len, flags) != 0) {
820 retval = bxattr_exit_ok;
824 * The xattr already exists we need to replace it.
826 flags = xattr_naming_space->flags | ATTR_REPLACE;
827 if (attr_set(jcr->last_fname, current_xattr->name,
828 current_xattr->value, current_xattr->value_len, flags) != 0) {
831 retval = bxattr_exit_ok;
834 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
835 jcr->last_fname, be.bstrerror());
836 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
837 jcr->last_fname, be.bstrerror());
843 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
844 jcr->last_fname, be.bstrerror());
845 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
846 jcr->last_fname, be.bstrerror());
852 xattr_drop_internal_table(xattr_value_list);
853 return bxattr_exit_ok;
856 xattr_drop_internal_table(xattr_value_list);
857 return bxattr_exit_error;
861 * Function pointers to the build and parse function to use for these xattrs.
863 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = irix_xattr_build_streams;
864 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = irix_xattr_parse_streams;
866 #elif defined(HAVE_DARWIN_OS) || \
867 defined(HAVE_LINUX_OS)
869 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
870 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
871 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
872 #error "Missing full support for the XATTR functions."
875 #ifdef HAVE_SYS_XATTR_H
876 #include <sys/xattr.h>
878 #error "Missing sys/xattr.h header file"
882 * Define the supported XATTR streams for this OS
884 #if defined(HAVE_DARWIN_OS)
885 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
886 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
887 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
888 #elif defined(HAVE_LINUX_OS)
889 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
890 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
891 static const char *xattr_skiplist[1] = { NULL };
895 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
896 * listxattr, getxattr and setxattr with an extra options argument
897 * which mimics the l variants of the functions when we specify
898 * XATTR_NOFOLLOW as the options value.
900 #if defined(HAVE_DARWIN_OS)
901 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
902 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
903 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
906 * Fallback to the non l-functions when those are not available.
908 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
909 #define lgetxattr getxattr
911 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
912 #define lsetxattr setxattr
914 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
915 #define llistxattr listxattr
919 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
922 char *xattr_list, *bp;
923 int cnt, xattr_count = 0;
924 int32_t xattr_list_len,
926 uint32_t expected_serialize_len = 0;
927 xattr_t *current_xattr;
928 alist *xattr_value_list = NULL;
929 bxattr_exit_code retval = bxattr_exit_error;
933 * First get the length of the available list with extended attributes.
935 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
936 switch (xattr_list_len) {
941 return bxattr_exit_ok;
943 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
944 jcr->last_fname, be.bstrerror());
945 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
946 jcr->last_fname, be.bstrerror());
947 return bxattr_exit_error;
951 return bxattr_exit_ok;
957 * Allocate room for the extented attribute list.
959 xattr_list = (char *)malloc(xattr_list_len + 1);
960 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
963 * Get the actual list of extended attributes names for a file.
965 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
966 switch (xattr_list_len) {
971 retval = bxattr_exit_ok;
974 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
975 jcr->last_fname, be.bstrerror());
976 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
977 jcr->last_fname, be.bstrerror());
984 xattr_list[xattr_list_len] = '\0';
986 xattr_value_list = New(alist(10, not_owned_by_alist));
989 * Walk the list of extended attributes names and retrieve the data.
990 * We already count the bytes needed for serializing the stream later on.
993 while ((bp - xattr_list) + 1 < xattr_list_len) {
998 * On some OSes you also get the acls in the extented attribute list.
999 * So we check if we are already backing up acls and if we do we
1000 * don't store the extended attribute with the same info.
1002 if (ff_pkt->flags & FO_ACL) {
1003 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1004 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1012 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1015 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1016 if (bstrcmp(bp, xattr_skiplist[cnt])) {
1023 name_len = strlen(bp);
1024 if (skip_xattr || name_len == 0) {
1025 bp = strchr(bp, '\0') + 1;
1026 Dmsg1(100, "Skipping xattr named %s\n", current_xattr->name);
1031 * Each xattr valuepair starts with a magic so we can parse it easier.
1033 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1034 current_xattr->magic = XATTR_MAGIC;
1035 expected_serialize_len += sizeof(current_xattr->magic);
1038 * Allocate space for storing the name.
1040 current_xattr->name_length = name_len;
1041 current_xattr->name = (char *)malloc(current_xattr->name_length);
1042 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
1044 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1047 * First see how long the value is for the extended attribute.
1049 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1050 switch (xattr_value_len) {
1055 retval = bxattr_exit_ok;
1056 free(current_xattr->name);
1057 free(current_xattr);
1060 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1061 jcr->last_fname, be.bstrerror());
1062 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1063 jcr->last_fname, be.bstrerror());
1064 free(current_xattr->name);
1065 free(current_xattr);
1070 current_xattr->value = NULL;
1071 current_xattr->value_length = 0;
1072 expected_serialize_len += sizeof(current_xattr->value_length);
1076 * Allocate space for storing the value.
1078 current_xattr->value = (char *)malloc(xattr_value_len);
1079 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1081 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1082 if (xattr_value_len < 0) {
1086 retval = bxattr_exit_ok;
1087 free(current_xattr->value);
1088 free(current_xattr->name);
1089 free(current_xattr);
1092 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1093 jcr->last_fname, be.bstrerror());
1094 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1095 jcr->last_fname, be.bstrerror());
1096 free(current_xattr->value);
1097 free(current_xattr->name);
1098 free(current_xattr);
1103 * Store the actual length of the value.
1105 current_xattr->value_length = xattr_value_len;
1106 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1109 * Protect ourself against things getting out of hand.
1111 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1112 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1113 jcr->last_fname, MAX_XATTR_STREAM);
1114 free(current_xattr->value);
1115 free(current_xattr->name);
1116 free(current_xattr);
1121 xattr_value_list->append(current_xattr);
1123 bp = strchr(bp, '\0') + 1;
1128 xattr_list = (char *)NULL;
1131 * If we found any xattr send them to the SD.
1133 if (xattr_count > 0) {
1135 * Serialize the datastream.
1137 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1138 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1140 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1145 xattr_drop_internal_table(xattr_value_list);
1148 * Send the datastream to the SD.
1150 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
1152 xattr_drop_internal_table(xattr_value_list);
1154 return bxattr_exit_ok;
1158 if (xattr_list != NULL) {
1161 if (xattr_value_list != NULL) {
1162 xattr_drop_internal_table(xattr_value_list);
1167 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
1169 xattr_t *current_xattr;
1170 alist *xattr_value_list;
1173 xattr_value_list = New(alist(10, not_owned_by_alist));
1175 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1176 xattr_drop_internal_table(xattr_value_list);
1177 return bxattr_exit_error;
1180 foreach_alist(current_xattr, xattr_value_list) {
1181 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1187 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
1188 jcr->last_fname, be.bstrerror());
1189 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1190 jcr->last_fname, be.bstrerror());
1196 xattr_drop_internal_table(xattr_value_list);
1197 return bxattr_exit_ok;
1200 xattr_drop_internal_table(xattr_value_list);
1201 return bxattr_exit_error;
1205 * Function pointers to the build and parse function to use for these xattrs.
1207 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
1208 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
1210 #elif defined(HAVE_FREEBSD_OS) || \
1211 defined(HAVE_NETBSD_OS) || \
1212 defined(HAVE_OPENBSD_OS)
1214 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1215 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1216 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1217 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1218 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1219 #error "Missing full support for the extattr functions."
1222 #ifdef HAVE_SYS_EXTATTR_H
1223 #include <sys/extattr.h>
1225 #error "Missing sys/extattr.h header file"
1228 #ifdef HAVE_LIBUTIL_H
1229 #include <libutil.h>
1232 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1233 #define extattr_get_link extattr_get_file
1235 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1236 #define extattr_set_link extattr_set_file
1238 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1239 #define extattr_list_link extattr_list_file
1242 #if defined(HAVE_FREEBSD_OS)
1243 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
1244 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1245 static const char *xattr_acl_skiplist[2] = { "system.posix1e.acl_access", NULL };
1246 static const char *xattr_skiplist[1] = { NULL };
1247 #elif defined(HAVE_NETBSD_OS)
1248 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
1249 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1250 static const char *xattr_acl_skiplist[1] = { NULL };
1251 static const char *xattr_skiplist[1] = { NULL };
1252 #elif defined(HAVE_OPENBSD_OS)
1253 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
1254 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1255 static const char *xattr_acl_skiplist[1] = { NULL };
1256 static const char *xattr_skiplist[1] = { NULL };
1259 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1263 int cnt, index, xattr_count = 0;
1264 int32_t xattr_list_len,
1266 uint32_t expected_serialize_len = 0;
1267 unsigned int namespace_index;
1269 char *current_attrnamespace = NULL;
1270 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1271 xattr_t *current_xattr;
1272 alist *xattr_value_list = NULL;
1273 bxattr_exit_code retval = bxattr_exit_error;
1276 xattr_value_list = New(alist(10, not_owned_by_alist));
1279 * Loop over all available xattr namespaces.
1281 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
1282 attrnamespace = os_default_xattr_namespaces[namespace_index];
1285 * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
1286 * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
1288 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1289 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
1290 attrnamespace, jcr->last_fname);
1291 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1292 attrnamespace, jcr->last_fname);
1297 * First get the length of the available list with extended attributes.
1298 * If we get EPERM on system namespace, don't return error.
1299 * This is expected for normal users trying to archive the system
1300 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1301 * they've decided to return EOPNOTSUPP instead.
1303 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1304 switch (xattr_list_len) {
1308 retval = bxattr_exit_ok;
1310 #if defined(EOPNOTSUPP)
1314 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1315 actuallyfree(current_attrnamespace);
1316 current_attrnamespace = NULL;
1323 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1324 jcr->last_fname, be.bstrerror());
1325 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1326 jcr->last_fname, be.bstrerror());
1337 * Allocate room for the extented attribute list.
1339 xattr_list = (char *)malloc(xattr_list_len + 1);
1340 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
1343 * Get the actual list of extended attributes names for a file.
1345 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
1346 switch (xattr_list_len) {
1350 retval = bxattr_exit_ok;
1353 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1354 jcr->last_fname, be.bstrerror());
1355 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1356 jcr->last_fname, be.bstrerror());
1363 xattr_list[xattr_list_len] = '\0';
1366 * Walk the list of extended attributes names and retrieve the data.
1367 * We already count the bytes needed for serializing the stream later on.
1369 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1373 * Print the current name into the buffer as its not null terminated we need to
1374 * use the length encoded in the string for copying only the needed bytes.
1376 cnt = xattr_list[index];
1377 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1378 cnt = ((int)sizeof(current_attrname) - 1);
1380 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1381 current_attrname[cnt] = '\0';
1384 * First make a xattr tuple of the current namespace and the name of the xattr.
1385 * e.g. something like user.<attrname> or system.<attrname>
1387 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
1390 * On some OSes you also get the acls in the extented attribute list.
1391 * So we check if we are already backing up acls and if we do we
1392 * don't store the extended attribute with the same info.
1394 if (ff_pkt->flags & FO_ACL) {
1395 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1396 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1404 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1407 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1408 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1416 Dmsg1(100, "Skipping xattr named %s\n", current_xattr->name);
1421 * Each xattr valuepair starts with a magic so we can parse it easier.
1423 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1424 current_xattr->magic = XATTR_MAGIC;
1425 expected_serialize_len += sizeof(current_xattr->magic);
1428 * Allocate space for storing the name.
1430 current_xattr->name_length = strlen(current_attrtuple);
1431 current_xattr->name = (char *)malloc(current_xattr->name_length);
1432 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
1434 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1437 * First see how long the value is for the extended attribute.
1439 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
1440 switch (xattr_value_len) {
1444 retval = bxattr_exit_ok;
1445 free(current_xattr->name);
1446 free(current_xattr);
1449 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1450 jcr->last_fname, be.bstrerror());
1451 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1452 jcr->last_fname, be.bstrerror());
1453 free(current_xattr->name);
1454 free(current_xattr);
1459 current_xattr->value = NULL;
1460 current_xattr->value_length = 0;
1461 expected_serialize_len += sizeof(current_xattr->value_length);
1465 * Allocate space for storing the value.
1467 current_xattr->value = (char *)malloc(xattr_value_len);
1468 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1470 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
1471 if (xattr_value_len < 0) {
1474 retval = bxattr_exit_ok;
1475 free(current_xattr->value);
1476 free(current_xattr->name);
1477 free(current_xattr);
1480 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1481 jcr->last_fname, be.bstrerror());
1482 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1483 jcr->last_fname, be.bstrerror());
1484 free(current_xattr->value);
1485 free(current_xattr->name);
1486 free(current_xattr);
1492 * Store the actual length of the value.
1494 current_xattr->value_length = xattr_value_len;
1495 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1498 * Protect ourself against things getting out of hand.
1500 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1501 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1502 jcr->last_fname, MAX_XATTR_STREAM);
1503 free(current_xattr->value);
1504 free(current_xattr->name);
1505 free(current_xattr);
1511 xattr_value_list->append(current_xattr);
1517 * Drop the local copy of the current_attrnamespace.
1519 actuallyfree(current_attrnamespace);
1520 current_attrnamespace = NULL;
1523 * We are done with this xattr list.
1526 xattr_list = (char *)NULL;
1530 * If we found any xattr send them to the SD.
1532 if (xattr_count > 0) {
1534 * Serialize the datastream.
1536 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1537 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1539 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1544 xattr_drop_internal_table(xattr_value_list);
1547 * Send the datastream to the SD.
1549 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
1551 xattr_drop_internal_table(xattr_value_list);
1553 return bxattr_exit_ok;
1557 if (current_attrnamespace != NULL) {
1558 actuallyfree(current_attrnamespace);
1560 if (xattr_list != NULL) {
1563 if (xattr_value_list != NULL) {
1564 xattr_drop_internal_table(xattr_value_list);
1569 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
1571 xattr_t *current_xattr;
1572 alist *xattr_value_list;
1573 int current_attrnamespace, cnt;
1574 char *attrnamespace, *attrname;
1577 xattr_value_list = New(alist(10, not_owned_by_alist));
1579 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1580 xattr_drop_internal_table(xattr_value_list);
1581 return bxattr_exit_error;
1584 foreach_alist(current_xattr, xattr_value_list) {
1586 * Try splitting the xattr_name into a namespace and name part.
1587 * The splitting character is a .
1589 attrnamespace = current_xattr->name;
1590 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1591 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1592 current_xattr->name, jcr->last_fname);
1593 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1594 current_xattr->name, jcr->last_fname);
1600 * Make sure the attrnamespace makes sense.
1602 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1603 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1604 attrnamespace, jcr->last_fname);
1605 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1606 attrnamespace, jcr->last_fname);
1611 * Try restoring the extended attribute.
1613 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1614 attrname, current_xattr->value, current_xattr->value_length);
1615 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1621 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1622 jcr->last_fname, be.bstrerror());
1623 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1624 jcr->last_fname, be.bstrerror());
1631 xattr_drop_internal_table(xattr_value_list);
1632 return bxattr_exit_ok;
1635 xattr_drop_internal_table(xattr_value_list);
1636 return bxattr_exit_error;
1640 * Function pointers to the build and parse function to use for these xattrs.
1642 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1643 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1645 #elif defined(HAVE_TRU64_OS)
1647 #if !defined(HAVE_GETPROPLIST) || \
1648 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1649 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1650 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1651 !defined(HAVE_SETPROPLIST)
1652 #error "Missing full support for the Extended Attributes functions."
1655 #ifdef HAVE_SYS_PROPLIST_H
1656 #include <sys/proplist.h>
1658 #error "Missing sys/proplist.h header file"
1662 * Define the supported XATTR streams for this OS
1664 static int os_default_xattr_streams[1] = { STREAM_XATTR_TRU64 };
1665 static const char *xattr_acl_skiplist[1] = { NULL };
1666 static const char *xattr_skiplist[1] = { NULL };
1668 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1674 int xattr_count = 0;
1677 int32_t xattr_list_len,
1680 uint32_t expected_serialize_len = 0;
1681 xattr_t *current_xattr;
1682 alist *xattr_value_list = NULL;
1683 struct proplistname_args prop_args;
1684 bxattr_exit_code retval = bxattr_exit_error;
1685 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1688 xattrbuf_size = sizeof_pool_memory(xattrbuf);
1689 xattrbuf_min_size = 0;
1690 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1691 xattrbuf, &xattrbuf_min_size);
1694 * See what xattr are available.
1696 switch (xattr_list_len) {
1700 retval = bacl_exit_ok;
1703 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1704 jcr->last_fname, be.bstrerror());
1705 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1706 jcr->last_fname, be.bstrerror());
1711 if (xattrbuf_min_size) {
1713 * The buffer isn't big enough to hold the xattr data, we now have
1714 * a minimum buffersize so we resize the buffer and try again.
1716 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1717 xattrbuf_size = xattrbuf_min_size + 1;
1718 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1719 xattrbuf, &xattrbuf_min_size);
1720 switch (xattr_list_len) {
1724 retval = bacl_exit_ok;
1727 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1728 jcr->last_fname, be.bstrerror());
1729 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1730 jcr->last_fname, be.bstrerror());
1736 * This should never happen as we sized the buffer according to the minimumsize
1737 * returned by a previous getproplist call. If it does happen things are fishy and
1738 * we are better of forgetting this xattr as it seems its list is changing at this
1739 * exact moment so we can never make a good backup copy of it.
1741 retval = bacl_exit_ok;
1750 retval = bacl_exit_ok;
1758 xattr_value_list = New(alist(10, not_owned_by_alist));
1761 * Walk the list of extended attributes names and retrieve the data.
1762 * We already count the bytes needed for serializing the stream later on.
1765 while (xattrbuf_size > 0) {
1767 * Call getproplist_entry to initialize name and value
1768 * pointers to entries position within buffer.
1770 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
1773 * On some OSes you also get the acls in the extented attribute list.
1774 * So we check if we are already backing up acls and if we do we
1775 * don't store the extended attribute with the same info.
1777 if (ff_pkt->flags & FO_ACL) {
1778 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1779 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
1787 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1790 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1791 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
1799 Dmsg1(100, "Skipping xattr named %s\n", current_xattr->name);
1804 * Each xattr valuepair starts with a magic so we can parse it easier.
1806 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1807 current_xattr->magic = XATTR_MAGIC;
1808 expected_serialize_len += sizeof(current_xattr->magic);
1810 current_xattr->name_length = strlen(xattr_name);
1811 current_xattr->name = bstrdup(xattr_name);
1813 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1815 current_xattr->value_length = *xattr_value_len;
1816 current_xattr->value = (char *)malloc(current_xattr->value_length);
1817 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
1819 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1822 * Protect ourself against things getting out of hand.
1824 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1825 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1826 jcr->last_fname, MAX_XATTR_STREAM);
1827 free(current_xattr->value);
1828 free(current_xattr->name);
1829 free(current_xattr);
1833 xattr_value_list->append(current_xattr);
1838 * If we found any xattr send them to the SD.
1840 if (xattr_count > 0) {
1842 * Serialize the datastream.
1844 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1845 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1847 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1853 * Send the datastream to the SD.
1855 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1859 if (xattr_value_list != NULL) {
1860 xattr_drop_internal_table(xattr_value_list);
1862 free_pool_memory(xattrbuf);
1867 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr, int stream)
1869 char *bp, *xattrbuf = NULL;
1870 int32_t xattrbuf_size, cnt;
1871 xattr_t *current_xattr;
1872 alist *xattr_value_list;
1875 xattr_value_list = New(alist(10, not_owned_by_alist));
1877 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1878 xattr_drop_internal_table(xattr_value_list);
1879 return bxattr_exit_error;
1883 * See how big the propertylist must be.
1886 foreach_alist(current_xattr, xattr_value_list) {
1887 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
1890 xattrbuf = (char *)malloc(xattrbuf_size);
1893 * Add all value pairs to the proplist.
1897 foreach_alist(current_xattr, xattr_value_list) {
1898 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
1899 current_xattr->value, &bp);
1905 if (cnt != xattrbuf_size) {
1906 Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
1908 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
1914 * Restore the list of extended attributes on the file.
1916 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
1921 retval = bacl_exit_ok;
1924 Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
1925 jcr->last_fname, be.bstrerror());
1926 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
1927 jcr->last_fname, be.bstrerror());
1937 xattr_drop_internal_table(xattr_value_list);
1938 return bxattr_exit_ok;
1944 xattr_drop_internal_table(xattr_value_list);
1945 return bxattr_exit_error;
1949 * Function pointers to the build and parse function to use for these xattrs.
1951 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_xattr_streams;
1952 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = tru64_parse_xattr_streams;
1954 #elif defined(HAVE_SUN_OS)
1956 * Solaris extended attributes were introduced in Solaris 9
1959 * Solaris extensible attributes were introduced in OpenSolaris
1960 * by PSARC 2007/315 Solaris extensible attributes are also
1961 * sometimes called extended system attributes.
1963 * man fsattr(5) on Solaris gives a wealth of info. The most
1964 * important bits are:
1966 * Attributes are logically supported as files within the file
1967 * system. The file system is therefore augmented with an
1968 * orthogonal name space of file attributes. Any file (includ-
1969 * ing attribute files) can have an arbitrarily deep attribute
1970 * tree associated with it. Attribute values are accessed by
1971 * file descriptors obtained through a special attribute inter-
1972 * face. This logical view of "attributes as files" allows the
1973 * leveraging of existing file system interface functionality
1974 * to support the construction, deletion, and manipulation of
1977 * The special files "." and ".." retain their accustomed
1978 * semantics within the attribute hierarchy. The "." attribute
1979 * file refers to the current directory and the ".." attribute
1980 * file refers to the parent directory. The unnamed directory
1981 * at the head of each attribute tree is considered the "child"
1982 * of the file it is associated with and the ".." file refers
1983 * to the associated file. For any non-directory file with
1984 * attributes, the ".." entry in the unnamed directory refers
1985 * to a file that is not a directory.
1987 * Conceptually, the attribute model is fully general. Extended
1988 * attributes can be any type of file (doors, links, direc-
1989 * tories, and so forth) and can even have their own attributes
1990 * (fully recursive). As a result, the attributes associated
1991 * with a file could be an arbitrarily deep directory hierarchy
1992 * where each attribute could have an equally complex attribute
1993 * tree associated with it. Not all implementations are able
1994 * to, or want to, support the full model. Implementation are
1995 * therefore permitted to reject operations that are not sup-
1996 * ported. For example, the implementation for the UFS file
1997 * system allows only regular files as attributes (for example,
1998 * no sub-directories) and rejects attempts to place attributes
2001 * The following list details the operations that are rejected
2002 * in the current implementation:
2004 * link Any attempt to create links between
2005 * attribute and non-attribute space
2006 * is rejected to prevent security-
2007 * related or otherwise sensitive
2008 * attributes from being exposed, and
2009 * therefore manipulable, as regular
2012 * rename Any attempt to rename between
2013 * attribute and non-attribute space
2014 * is rejected to prevent an already
2015 * linked file from being renamed and
2016 * thereby circumventing the link res-
2019 * mkdir, symlink, mknod Any attempt to create a "non-
2020 * regular" file in attribute space is
2021 * rejected to reduce the functional-
2022 * ity, and therefore exposure and
2023 * risk, of the initial implementa-
2026 * The entire available name space has been allocated to "gen-
2027 * eral use" to bring the implementation in line with the NFSv4
2028 * draft standard [NFSv4]. That standard defines "named attri-
2029 * butes" (equivalent to Solaris Extended Attributes) with no
2030 * naming restrictions. All Sun applications making use of
2031 * opaque extended attributes will use the prefix "SUNW".
2034 #ifdef HAVE_SYS_ATTR_H
2035 #include <sys/attr.h>
2042 #ifdef HAVE_SYS_NVPAIR_H
2043 #include <sys/nvpair.h>
2046 #ifdef HAVE_SYS_ACL_H
2047 #include <sys/acl.h>
2050 #if !defined(HAVE_OPENAT) || \
2051 !defined(HAVE_UNLINKAT) || \
2052 !defined(HAVE_FCHOWNAT) || \
2053 !defined(HAVE_FUTIMESAT)
2054 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2058 * Define the supported XATTR streams for this OS
2060 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2061 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
2063 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
2064 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2067 * This code creates a temporary cache with entries for each xattr which has
2068 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2070 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2072 xattr_link_cache_entry_t *ptr;
2074 foreach_alist(ptr, jcr->xattr_data->link_cache) {
2075 if (ptr && ptr->inum == inum) {
2082 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2084 xattr_link_cache_entry_t *ptr;
2086 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2087 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
2089 bstrncpy(ptr->target, target, sizeof(ptr->target));
2090 jcr->xattr_data->link_cache->append(ptr);
2093 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2095 * This function returns true if a non default extended system attribute
2096 * list is associated with fd and returns false when an error has occured
2097 * or when only extended system attributes other than archive,
2098 * av_modified or crtime are set.
2100 * The function returns true for the following cases:
2102 * - any extended system attribute other than the default attributes
2103 * ('archive', 'av_modified' and 'crtime') is set
2104 * - nvlist has NULL name string
2105 * - nvpair has data type of 'nvlist'
2106 * - default data type.
2108 static bool solaris_has_non_transient_extensible_attributes(int fd)
2116 bool retval = false;
2118 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2123 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2124 name = nvpair_name(pair);
2127 fattr = name_to_attr(name);
2133 type = nvpair_type(pair);
2135 case DATA_TYPE_BOOLEAN_VALUE:
2136 if (nvpair_value_boolean_value(pair, &value) != 0) {
2139 if (value && fattr != F_ARCHIVE &&
2140 fattr != F_AV_MODIFIED) {
2145 case DATA_TYPE_UINT64_ARRAY:
2146 if (fattr != F_CRTIME) {
2151 case DATA_TYPE_NVLIST:
2159 if (response != NULL) {
2160 nvlist_free(response);
2164 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2166 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2168 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2169 * There is no need to store those acls as we already store the stat bits too.
2171 static bool acl_is_trivial(int count, aclent_t *entries)
2176 for (n = 0; n < count; n++) {
2178 if (!(ace->a_type == USER_OBJ ||
2179 ace->a_type == GROUP_OBJ ||
2180 ace->a_type == OTHER_OBJ ||
2181 ace->a_type == CLASS_OBJ))
2186 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2188 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2191 #ifdef HAVE_EXTENDED_ACL
2197 * See if this attribute has an ACL
2199 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2200 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2202 * See if there is a non trivial acl on the file.
2204 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2205 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2208 return bxattr_exit_ok;
2210 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2211 attrname, jcr->last_fname, be.bstrerror());
2212 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2213 attrname, jcr->last_fname, be.bstrerror());
2214 return bxattr_exit_error;
2219 #if defined(ACL_SID_FMT)
2221 * New format flag added in newer Solaris versions.
2223 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2225 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2226 #endif /* ACL_SID_FMT */
2228 *acl_text = acl_totext(aclp, flags);
2236 return bxattr_exit_ok;
2237 #else /* HAVE_EXTENDED_ACL */
2239 aclent_t *acls = NULL;
2243 * See if this attribute has an ACL
2246 n = facl(fd, GETACLCNT, 0, NULL);
2248 n = acl(attrname, GETACLCNT, 0, NULL);
2251 if (n >= MIN_ACL_ENTRIES) {
2252 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2253 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2254 acl(attrname, GETACL, n, acls) != n) {
2258 return bxattr_exit_ok;
2260 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2261 attrname, jcr->last_fname, be.bstrerror());
2262 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2263 attrname, jcr->last_fname, be.bstrerror());
2265 return bxattr_exit_error;
2270 * See if there is a non trivial acl on the file.
2272 if (!acl_is_trivial(n, acls)) {
2273 if ((*acl_text = acltotext(acls, n)) == NULL) {
2274 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2275 attrname, jcr->last_fname, be.bstrerror());
2276 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2277 attrname, jcr->last_fname, be.bstrerror());
2279 return bxattr_exit_error;
2289 return bxattr_exit_ok;
2290 #endif /* HAVE_EXTENDED_ACL */
2292 #else /* HAVE_ACL */
2293 return bxattr_exit_ok;
2294 #endif /* HAVE_ACL */
2298 * Forward declaration for recursive function call.
2300 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2303 * Save an extended or extensible attribute.
2304 * This is stored as an opaque stream of bytes with the following encoding:
2306 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2308 * or for a hardlinked or symlinked attribute
2310 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2312 * xattr_name can be a subpath relative to the file the xattr is on.
2313 * stat_buffer is the string representation of the stat struct.
2314 * acl_string is an acl text when a non trivial acl is set on the xattr.
2315 * actual_xattr_data is the content of the xattr file.
2317 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2318 const char *attrname, bool toplevel_hidden_dir, int stream)
2323 xattr_link_cache_entry_t *xlce;
2324 char target_attrname[PATH_MAX];
2325 char link_source[PATH_MAX];
2326 char *acl_text = NULL;
2327 char attribs[MAXSTRING];
2328 char buffer[XATTR_BUFSIZ];
2329 bxattr_exit_code retval = bxattr_exit_error;
2332 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2335 * Get the stats of the extended or extensible attribute.
2337 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2340 retval = bxattr_exit_ok;
2343 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2344 target_attrname, jcr->last_fname, be.bstrerror());
2345 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2346 target_attrname, jcr->last_fname, be.bstrerror());
2352 * Based on the filetype perform the correct action. We support most filetypes here, more
2353 * then the actual implementation on Solaris supports so some code may never get executed
2354 * due to limitations in the implementation.
2356 switch (st.st_mode & S_IFMT) {
2361 * Get any acl on the xattr.
2363 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2367 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2368 * Encode the stat struct into an ASCII representation.
2370 encode_stat(attribs, &st, 0, stream);
2371 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2372 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2376 * Get any acl on the xattr.
2378 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2382 * See if this is the toplevel_hidden_dir being saved.
2384 if (toplevel_hidden_dir) {
2386 * Save the data for later storage when we encounter a real xattr. We store the data
2387 * in the jcr->xattr_data->content buffer and flush that just before sending out the
2388 * first real xattr. Encode the stat struct into an ASCII representation and jump
2389 * out of the function.
2391 encode_stat(attribs, &st, 0, stream);
2392 cnt = bsnprintf(buffer, sizeof(buffer),
2394 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2395 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2396 jcr->xattr_data->content_length = cnt;
2400 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2401 * Encode the stat struct into an ASCII representation.
2403 encode_stat(attribs, &st, 0, stream);
2404 cnt = bsnprintf(buffer, sizeof(buffer),
2406 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2411 * If this is a hardlinked file check the inode cache for a hit.
2413 if (st.st_nlink > 1) {
2415 * See if the cache already knows this inode number.
2417 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2419 * Generate a xattr encoding with the reference to the target in there.
2421 encode_stat(attribs, &st, st.st_ino, stream);
2422 cnt = bsnprintf(buffer, sizeof(buffer),
2424 target_attrname, 0, attribs, 0, xlce->target, 0);
2425 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2426 jcr->xattr_data->content_length = cnt;
2427 retval = send_xattr_stream(jcr, stream);
2430 * For a hard linked file we are ready now, no need to recursively save the attributes.
2436 * Store this hard linked file in the cache.
2437 * Store the name relative to the top level xattr space.
2439 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2443 * Get any acl on the xattr.
2445 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2450 * Encode the stat struct into an ASCII representation.
2452 encode_stat(attribs, &st, 0, stream);
2453 cnt = bsnprintf(buffer, sizeof(buffer),
2455 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2458 * Open the extended or extensible attribute file.
2460 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2463 retval = bxattr_exit_ok;
2466 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2467 target_attrname, jcr->last_fname, be.bstrerror());
2468 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2469 target_attrname, jcr->last_fname, be.bstrerror());
2476 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2477 * Encode the stat struct into an ASCII representation.
2479 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2482 retval = bxattr_exit_ok;
2485 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2486 target_attrname, jcr->last_fname, be.bstrerror());
2487 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2488 target_attrname, jcr->last_fname, be.bstrerror());
2494 * Generate a xattr encoding with the reference to the target in there.
2496 encode_stat(attribs, &st, st.st_ino, stream);
2497 cnt = bsnprintf(buffer, sizeof(buffer),
2499 target_attrname, 0, attribs, 0, link_source, 0);
2500 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2501 jcr->xattr_data->content_length = cnt;
2502 retval = send_xattr_stream(jcr, stream);
2504 if (retval == bxattr_exit_ok) {
2505 jcr->xattr_data->nr_saved++;
2509 * For a soft linked file we are ready now, no need to recursively save the attributes.
2517 * See if this is the first real xattr being saved.
2518 * If it is save the toplevel_hidden_dir attributes first.
2519 * This is easy as its stored already in the jcr->xattr_data->content buffer.
2521 if (jcr->xattr_data->nr_saved == 0) {
2522 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2523 if (retval != bxattr_exit_ok) {
2526 jcr->xattr_data->nr_saved++;
2529 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2530 jcr->xattr_data->content_length = cnt;
2533 * Only dump the content of regular files.
2535 switch (st.st_mode & S_IFMT) {
2537 if (st.st_size > 0) {
2539 * Protect ourself against things getting out of hand.
2541 if (st.st_size >= MAX_XATTR_STREAM) {
2542 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2543 jcr->last_fname, MAX_XATTR_STREAM);
2547 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2548 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
2549 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
2550 jcr->xattr_data->content_length += cnt;
2554 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
2555 target_attrname, jcr->last_fname);
2556 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2557 target_attrname, jcr->last_fname);
2568 retval = send_xattr_stream(jcr, stream);
2569 if (retval == bxattr_exit_ok) {
2570 jcr->xattr_data->nr_saved++;
2575 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2576 * available on this extended attribute.
2579 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2582 * The recursive call could change our working dir so change back to the wanted workdir.
2584 if (fchdir(fd) < 0) {
2587 retval = bxattr_exit_ok;
2590 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2591 jcr->last_fname, be.bstrerror());
2592 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2593 jcr->last_fname, fd, be.bstrerror());
2600 if (acl_text != NULL) {
2609 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2612 int fd, filefd = -1, attrdirfd = -1;
2615 char current_xattr_namespace[PATH_MAX];
2616 bxattr_exit_code retval = bxattr_exit_error;
2620 * Determine what argument to use. Use attr_parent when set
2621 * (recursive call) or jcr->last_fname for first call. Also save
2622 * the current depth of the xattr_space we are in.
2626 if (xattr_namespace) {
2627 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2628 xattr_namespace, attr_parent);
2630 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2633 name = jcr->last_fname;
2634 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2638 * Open the file on which to save the xattrs read-only.
2640 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2643 retval = bxattr_exit_ok;
2646 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2647 jcr->last_fname, be.bstrerror());
2648 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2649 jcr->last_fname, be.bstrerror());
2655 * Open the xattr naming space.
2657 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2661 * Gentile way of the system saying this type of xattr layering is not supported.
2662 * Which is not problem we just forget about this this xattr.
2663 * But as this is not an error we return a positive return value.
2665 retval = bxattr_exit_ok;
2668 retval = bxattr_exit_ok;
2671 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2672 name, jcr->last_fname, be.bstrerror());
2673 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2674 name, jcr->last_fname, be.bstrerror());
2680 * We need to change into the attribute directory to determine if each of the
2681 * attributes should be saved.
2683 if (fchdir(attrdirfd) < 0) {
2684 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2685 jcr->last_fname, be.bstrerror());
2686 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2687 jcr->last_fname, attrdirfd, be.bstrerror());
2692 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2693 * else because the readdir returns "." entry after the extensible attr entry.
2694 * And as we want this entry before anything else we better just save its data.
2697 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2698 true, STREAM_XATTR_SOLARIS);
2700 if ((fd = dup(attrdirfd)) == -1 ||
2701 (dirp = fdopendir(fd)) == (DIR *)NULL) {
2702 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2703 jcr->last_fname, be.bstrerror());
2704 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
2705 jcr->last_fname, fd, be.bstrerror());
2711 * Walk the namespace.
2713 while ((dp = readdir(dirp)) != NULL) {
2715 * Skip only the toplevel . dir.
2717 if (!attr_parent && bstrcmp(dp->d_name, "."))
2721 * Skip all .. directories
2723 if (bstrcmp(dp->d_name, ".."))
2726 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2727 current_xattr_namespace, dp->d_name, jcr->last_fname);
2729 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2731 * We are not interested in read-only extensible attributes.
2733 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2734 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2735 current_xattr_namespace, dp->d_name, jcr->last_fname);
2741 * We are only interested in read-write extensible attributes
2742 * when they contain non-transient values.
2744 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2746 * Determine if there are non-transient system attributes at the toplevel.
2747 * We need to provide a fd to the open file.
2749 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2750 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2751 current_xattr_namespace, dp->d_name, jcr->last_fname);
2758 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2759 false, STREAM_XATTR_SOLARIS_SYS);
2762 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2767 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2768 false, STREAM_XATTR_SOLARIS);
2772 retval = bxattr_exit_ok;
2775 if (attrdirfd != -1)
2783 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
2785 #ifdef HAVE_EXTENDED_ACL
2790 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
2791 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
2793 return bxattr_exit_error;
2796 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
2797 acl_set(attrname, aclp) != 0) {
2798 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2799 attrname, jcr->last_fname, be.bstrerror());
2800 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2801 attrname, jcr->last_fname, be.bstrerror());
2802 return bxattr_exit_error;
2808 return bxattr_exit_ok;
2810 #else /* HAVE_EXTENDED_ACL */
2812 aclent_t *acls = NULL;
2815 acls = aclfromtext(acl_text, &n);
2817 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
2818 acl(attrname, SETACL, n, acls) != 0) {
2819 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2820 attrname, jcr->last_fname, be.bstrerror());
2821 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2822 attrname, jcr->last_fname, be.bstrerror());
2823 return bxattr_exit_error;
2830 return bxattr_exit_ok;
2832 #endif /* HAVE_EXTENDED_ACL */
2835 #endif /* HAVE_ACL */
2837 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
2839 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
2840 int used_bytes, total_bytes, cnt;
2841 char *bp, *target_attrname, *attribs;
2842 char *linked_target = NULL;
2843 char *acl_text = NULL;
2847 struct timeval times[2];
2848 bxattr_exit_code retval = bxattr_exit_error;
2852 * Parse the xattr stream. First the part that is the same for all xattrs.
2855 total_bytes = jcr->xattr_data->content_length;
2858 * The name of the target xattr has a leading / we are not interested
2859 * in that so skip it when decoding the string. We always start a the /
2860 * of the xattr space anyway.
2862 target_attrname = jcr->xattr_data->content + 1;
2863 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
2864 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2870 * Open the file on which to restore the xattrs read-only.
2872 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
2873 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2874 jcr->last_fname, be.bstrerror());
2875 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2876 jcr->last_fname, be.bstrerror());
2881 * Open the xattr naming space and make it the current working dir.
2883 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2884 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
2885 jcr->last_fname, be.bstrerror());
2886 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
2887 jcr->last_fname, be.bstrerror());
2891 if (fchdir(attrdirfd) < 0) {
2892 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2893 jcr->last_fname, be.bstrerror());
2894 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2895 jcr->last_fname, attrdirfd, be.bstrerror());
2900 * Try to open the correct xattr subdir based on the target_attrname given.
2901 * e.g. check if its a subdir attrname. Each / in the string makes us go
2904 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2907 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2908 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2909 target_attrname, jcr->last_fname, be.bstrerror());
2910 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2911 target_attrname, jcr->last_fname, be.bstrerror());
2919 * Open the xattr naming space.
2921 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2922 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2923 target_attrname, jcr->last_fname, be.bstrerror());
2924 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2925 target_attrname, jcr->last_fname, be.bstrerror());
2933 * Make the xattr space our current workingdir.
2935 if (fchdir(attrdirfd) < 0) {
2936 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2937 target_attrname, jcr->last_fname, be.bstrerror());
2938 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2939 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2943 target_attrname = ++bp;
2947 * Decode the attributes from the stream.
2949 decode_stat(attribs, &st, &inum);
2952 * Decode the next field (acl_text).
2954 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2955 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2961 * Based on the filetype perform the correct action. We support most filetypes here, more
2962 * then the actual implementation on Solaris supports so some code may never get executed
2963 * due to limitations in the implementation.
2965 switch (st.st_mode & S_IFMT) {
2968 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2970 unlinkat(attrdirfd, target_attrname, 0);
2971 if (mkfifo(target_attrname, st.st_mode) < 0) {
2972 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
2973 target_attrname, jcr->last_fname, be.bstrerror());
2974 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
2975 target_attrname, jcr->last_fname, be.bstrerror());
2982 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2984 unlinkat(attrdirfd, target_attrname, 0);
2985 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
2986 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
2987 target_attrname, jcr->last_fname, be.bstrerror());
2988 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
2989 target_attrname, jcr->last_fname, be.bstrerror());
2995 * If its not the hidden_dir create the entry.
2996 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2998 if (!bstrcmp(target_attrname, ".")) {
2999 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3000 if (mkdir(target_attrname, st.st_mode) < 0) {
3001 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3002 target_attrname, jcr->last_fname, be.bstrerror());
3003 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3004 target_attrname, jcr->last_fname, be.bstrerror());
3011 * See if this is a hard linked file. e.g. inum != 0
3016 unlinkat(attrdirfd, target_attrname, 0);
3017 if (link(linked_target, target_attrname) < 0) {
3018 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3019 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3020 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3021 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3026 * Successfully restored xattr.
3028 retval = bxattr_exit_ok;
3031 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3032 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
3036 if (used_bytes < (total_bytes - 1))
3040 * Restore the actual xattr.
3042 if (!is_extensible) {
3043 unlinkat(attrdirfd, target_attrname, 0);
3046 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3047 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3048 target_attrname, jcr->last_fname, be.bstrerror());
3049 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3050 target_attrname, jcr->last_fname, be.bstrerror());
3056 * Restore the actual data.
3058 if (st.st_size > 0) {
3059 used_bytes = (data - jcr->xattr_data->content);
3060 cnt = total_bytes - used_bytes;
3063 * Do a sanity check, the st.st_size should be the same as the number of bytes
3064 * we have available as data of the stream.
3066 if (cnt != st.st_size) {
3067 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3068 target_attrname, jcr->last_fname);
3069 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3070 target_attrname, jcr->last_fname);
3075 cnt = write(attrfd, data, cnt);
3077 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3078 target_attrname, jcr->last_fname, be.bstrerror());
3079 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3080 target_attrname, jcr->last_fname, be.bstrerror());
3086 cnt = total_bytes - used_bytes;
3092 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3096 if (symlink(linked_target, target_attrname) < 0) {
3097 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3098 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3099 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3100 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3105 * Successfully restored xattr.
3107 retval = bxattr_exit_ok;
3114 * Restore owner and acl for non extensible attributes.
3116 if (!is_extensible) {
3117 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3121 * Gentile way of the system saying this type of xattr layering is not supported.
3122 * But as this is not an error we return a positive return value.
3124 retval = bxattr_exit_ok;
3127 retval = bxattr_exit_ok;
3130 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3131 target_attrname, jcr->last_fname, be.bstrerror());
3132 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3133 target_attrname, jcr->last_fname, be.bstrerror());
3140 if (acl_text && *acl_text)
3141 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3143 #endif /* HAVE_ACL */
3146 * For a non extensible attribute restore access and modification time on the xattr.
3148 if (!is_extensible) {
3149 times[0].tv_sec = st.st_atime;
3150 times[0].tv_usec = 0;
3151 times[1].tv_sec = st.st_mtime;
3152 times[1].tv_usec = 0;
3154 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3155 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3156 target_attrname, jcr->last_fname, be.bstrerror());
3157 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3158 target_attrname, jcr->last_fname, be.bstrerror());
3164 * Successfully restored xattr.
3166 retval = bxattr_exit_ok;
3170 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3172 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3179 if (attrdirfd != -1) {
3188 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3191 bxattr_exit_code retval = bxattr_exit_ok;
3194 * First see if extended attributes or extensible attributes are present.
3195 * If not just pretend things went ok.
3197 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3198 jcr->xattr_data->nr_saved = 0;
3199 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
3202 * As we change the cwd in the save function save the current cwd
3203 * for restore after return from the solaris_save_xattrs function.
3205 getcwd(cwd, sizeof(cwd));
3206 retval = solaris_save_xattrs(jcr, NULL, NULL);
3208 delete jcr->xattr_data->link_cache;
3209 jcr->xattr_data->link_cache = NULL;
3214 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
3217 bool is_extensible = false;
3218 bxattr_exit_code retval;
3221 * First make sure we can restore xattr on the filesystem.
3224 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3225 case STREAM_XATTR_SOLARIS_SYS:
3226 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3227 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
3228 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3230 return bxattr_exit_error;
3233 is_extensible = true;
3236 case STREAM_XATTR_SOLARIS:
3237 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3238 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
3239 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3241 return bxattr_exit_error;
3245 return bxattr_exit_error;
3249 * As we change the cwd in the restore function save the current cwd
3250 * for restore after return from the solaris_restore_xattrs function.
3252 getcwd(cwd, sizeof(cwd));
3253 retval = solaris_restore_xattrs(jcr, is_extensible);
3260 * Function pointers to the build and parse function to use for these xattrs.
3262 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
3263 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
3265 #endif /* defined(HAVE_SUN_OS) */
3268 * Entry points when compiled with support for XATTRs on a supported platform.
3270 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3272 if (os_build_xattr_streams) {
3273 return (*os_build_xattr_streams)(jcr, ff_pkt);
3275 return bxattr_exit_error;
3278 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
3282 if (os_parse_xattr_streams) {
3284 * See if we can parse this stream, and ifso give it a try.
3286 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3287 if (os_default_xattr_streams[cnt] == stream) {
3288 return (*os_parse_xattr_streams)(jcr, stream);
3293 * Issue a warning and discard the message. But pretend the restore was ok.
3295 Jmsg2(jcr, M_WARNING, 0,
3296 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3297 jcr->last_fname, stream);
3298 return bxattr_exit_error;