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 two of the GNU 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 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 * - Darwin (Extended Attributes)
36 * - Linux (Extended Attributes)
37 * - NetBSD (Extended Attributes)
38 * - FreeBSD (Extended Attributes)
39 * - OpenBSD (Extended Attributes)
40 * (As it seems either they never implemented xattr or they are removed
41 * the support as it stated it was in version 3.1 but the current syscall
42 * tabled shows the extattr_ functions are not implemented. So as such we
43 * might eventually support xattr on OpenBSD when they implemented them using
44 * the same interface as FreeBSD and NetBSD.
45 * - Solaris (Extended Attributes and Extensible Attributes)
47 * Written by Marco van Wieringen, November MMVIII
54 #if !defined(HAVE_XATTR)
56 * Entry points when compiled without support for XATTRs or on an unsupported platform.
58 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
60 return bxattr_exit_fatal;
63 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
65 return bxattr_exit_fatal;
69 * Send a XATTR stream to the SD.
71 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
73 BSOCK *sd = jcr->store_bsock;
75 #ifdef FD_NO_SEND_TEST
76 return bxattr_exit_ok;
82 if (jcr->xattr_data->content_length <= 0) {
83 return bxattr_exit_ok;
89 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
90 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
92 return bxattr_exit_fatal;
96 * Send the buffer to the storage deamon
98 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
100 sd->msg = jcr->xattr_data->content;
101 sd->msglen = jcr->xattr_data->content_length;
105 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
107 return bxattr_exit_fatal;
110 jcr->JobBytes += sd->msglen;
112 if (!sd->signal(BNET_EOD)) {
113 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
115 return bxattr_exit_fatal;
117 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
118 return bxattr_exit_ok;
122 * First some generic functions for OSes that use the same xattr encoding scheme.
124 #if defined(HAVE_DARWIN_OS) || \
125 defined(HAVE_LINUX_OS) || \
126 defined(HAVE_NETBSD_OS) || \
127 defined(HAVE_FREEBSD_OS) || \
128 defined(HAVE_OPENBSD_OS)
130 static void xattr_drop_internal_table(alist *xattr_value_list)
132 xattr_t *current_xattr;
135 * Walk the list of xattrs and free allocated memory on traversing.
137 foreach_alist(current_xattr, xattr_value_list) {
139 * See if we can shortcut.
141 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
144 free(current_xattr->name);
146 if (current_xattr->value_length > 0)
147 free(current_xattr->value);
152 delete xattr_value_list;
156 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
157 * which encodes one or more xattr_t structures.
159 * The Serialized stream consists of the following elements:
160 * magic - A magic string which makes it easy to detect any binary incompatabilites
161 * name_length - The length of the following xattr name
162 * name - The name of the extended attribute
163 * value_length - The length of the following xattr data
164 * value - The actual content of the extended attribute
166 * This is repeated 1 or more times.
169 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, alist *xattr_value_list)
171 xattr_t *current_xattr;
175 * Make sure the serialized stream fits in the poolmem buffer.
176 * We allocate some more to be sure the stream is gonna fit.
178 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
179 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
182 * Walk the list of xattrs and serialize the data.
184 foreach_alist(current_xattr, xattr_value_list) {
186 * See if we can shortcut.
188 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
191 ser_uint32(current_xattr->magic);
192 ser_uint32(current_xattr->name_length);
193 ser_bytes(current_xattr->name, current_xattr->name_length);
195 ser_uint32(current_xattr->value_length);
196 ser_bytes(current_xattr->value, current_xattr->value_length);
199 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
200 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
202 return jcr->xattr_data->content_length;
205 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
208 xattr_t *current_xattr;
209 bxattr_exit_code retval = bxattr_exit_ok;
212 * Parse the stream and call restore_xattr_on_file for each extended attribute.
214 * Start unserializing the data. We keep on looping while we have not
215 * unserialized all bytes in the stream.
217 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
218 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
220 * First make sure the magic is present. This way we can easily catch corruption.
221 * Any missing MAGIC is fatal we do NOT try to continue.
224 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
225 unser_uint32(current_xattr->magic);
226 if (current_xattr->magic != XATTR_MAGIC) {
227 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
229 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
232 return bxattr_exit_error;
236 * Decode the valuepair. First decode the length of the name.
238 unser_uint32(current_xattr->name_length);
241 * Allocate room for the name and decode its content.
243 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
244 unser_bytes(current_xattr->name, current_xattr->name_length);
247 * The xattr_name needs to be null terminated for lsetxattr.
249 current_xattr->name[current_xattr->name_length] = '\0';
252 * Decode the value length.
254 unser_uint32(current_xattr->value_length);
257 * Allocate room for the value and decode its content.
259 current_xattr->value = (char *)malloc(current_xattr->value_length);
260 unser_bytes(current_xattr->value, current_xattr->value_length);
262 xattr_value_list->append(current_xattr);
265 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
271 * This is a supported OS, See what kind of interface we should use.
273 #if defined(HAVE_DARWIN_OS) || \
274 defined(HAVE_LINUX_OS)
276 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
277 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
278 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
279 #error "Missing either full support for the LXATTR or XATTR functions."
282 #ifdef HAVE_SYS_XATTR_H
283 #include <sys/xattr.h>
285 #error "Missing sys/xattr.h header file"
289 * Define the supported XATTR streams for this OS
291 #if defined(HAVE_DARWIN_OS)
292 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
293 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
294 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
295 #elif defined(HAVE_LINUX_OS)
296 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
297 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
298 static const char *xattr_skiplist[1] = { NULL };
302 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
303 * listxattr, getxattr and setxattr with an extra options argument
304 * which mimics the l variants of the functions when we specify
305 * XATTR_NOFOLLOW as the options value.
307 #if defined(HAVE_DARWIN_OS)
308 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
309 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
310 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
313 * Fallback to the non l-functions when those are not available.
315 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
316 #define lgetxattr getxattr
318 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
319 #define lsetxattr setxattr
321 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
322 #define llistxattr listxattr
326 static bxattr_exit_code linux_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
329 char *xattr_list, *bp;
330 int cnt, xattr_count = 0;
331 int32_t xattr_list_len,
333 uint32_t expected_serialize_len = 0;
334 xattr_t *current_xattr;
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 = llistxattr(jcr->last_fname, NULL, 0);
343 if (xattr_list_len < 0) {
346 return bxattr_exit_ok;
348 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
349 jcr->last_fname, be.bstrerror());
350 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
351 jcr->last_fname, be.bstrerror());
352 return bxattr_exit_error;
354 } else if (xattr_list_len == 0) {
355 return bxattr_exit_ok;
359 * Allocate room for the extented attribute list.
361 xattr_list = (char *)malloc(xattr_list_len + 1);
362 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
365 * Get the actual list of extended attributes names for a file.
367 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
368 if (xattr_list_len < 0) {
371 retval = bxattr_exit_ok;
374 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
375 jcr->last_fname, be.bstrerror());
376 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
377 jcr->last_fname, be.bstrerror());
381 xattr_list[xattr_list_len] = '\0';
383 xattr_value_list = New(alist(10, not_owned_by_alist));
386 * Walk the list of extended attributes names and retrieve the data.
387 * We already count the bytes needed for serializing the stream later on.
390 while ((bp - xattr_list) + 1 < xattr_list_len) {
395 * On some OSes you also get the acls in the extented attribute list.
396 * So we check if we are already backing up acls and if we do we
397 * don't store the extended attribute with the same info.
399 if (ff_pkt->flags & FO_ACL) {
400 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
401 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
409 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
412 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
413 if (bstrcmp(bp, xattr_skiplist[cnt])) {
420 name_len = strlen(bp);
421 if (skip_xattr || name_len == 0) {
422 bp = strchr(bp, '\0') + 1;
427 * Each xattr valuepair starts with a magic so we can parse it easier.
429 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
430 current_xattr->magic = XATTR_MAGIC;
431 expected_serialize_len += sizeof(current_xattr->magic);
434 * Allocate space for storing the name.
436 current_xattr->name_length = name_len;
437 current_xattr->name = (char *)malloc(current_xattr->name_length);
438 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
440 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
443 * First see how long the value is for the extended attribute.
445 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
446 if (xattr_value_len < 0) {
449 retval = bxattr_exit_ok;
450 free(current_xattr->name);
454 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
455 jcr->last_fname, be.bstrerror());
456 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
457 jcr->last_fname, be.bstrerror());
458 free(current_xattr->name);
465 * Allocate space for storing the value.
467 current_xattr->value = (char *)malloc(xattr_value_len);
468 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
470 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
471 if (xattr_value_len < 0) {
474 retval = bxattr_exit_ok;
475 free(current_xattr->value);
476 free(current_xattr->name);
480 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
481 jcr->last_fname, be.bstrerror());
482 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
483 jcr->last_fname, be.bstrerror());
484 free(current_xattr->value);
485 free(current_xattr->name);
492 * Store the actual length of the value.
494 current_xattr->value_length = xattr_value_len;
495 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
498 * Protect ourself against things getting out of hand.
500 if (expected_serialize_len >= MAX_XATTR_STREAM) {
501 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
502 jcr->last_fname, MAX_XATTR_STREAM);
503 free(current_xattr->value);
504 free(current_xattr->name);
509 xattr_value_list->append(current_xattr);
511 bp = strchr(bp, '\0') + 1;
515 xattr_list = (char *)NULL;
518 * If we found any xattr send them to the SD.
520 if (xattr_count > 0) {
522 * Serialize the datastream.
524 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
525 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
527 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
532 xattr_drop_internal_table(xattr_value_list);
535 * Send the datastream to the SD.
537 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
539 xattr_drop_internal_table(xattr_value_list);
541 return bxattr_exit_ok;
545 if (xattr_list != NULL) {
548 if (xattr_value_list != NULL) {
549 xattr_drop_internal_table(xattr_value_list);
554 static bxattr_exit_code linux_xattr_parse_streams(JCR *jcr, int stream)
556 xattr_t *current_xattr;
557 alist *xattr_value_list;
560 xattr_value_list = New(alist(10, not_owned_by_alist));
562 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
563 xattr_drop_internal_table(xattr_value_list);
564 return bxattr_exit_error;
567 foreach_alist(current_xattr, xattr_value_list) {
568 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
573 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
574 jcr->last_fname, be.bstrerror());
575 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
576 jcr->last_fname, be.bstrerror());
582 xattr_drop_internal_table(xattr_value_list);
583 return bxattr_exit_ok;
586 xattr_drop_internal_table(xattr_value_list);
587 return bxattr_exit_error;
591 * Function pointers to the build and parse function to use for these xattrs.
593 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = linux_xattr_build_streams;
594 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = linux_xattr_parse_streams;
596 #elif defined(HAVE_FREEBSD_OS) || \
597 defined(HAVE_NETBSD_OS) || \
598 defined(HAVE_OPENBSD_OS)
600 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
601 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
602 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
603 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
604 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
605 #error "Missing full support for the extattr functions."
608 #ifdef HAVE_SYS_EXTATTR_H
609 #include <sys/extattr.h>
611 #error "Missing sys/extattr.h header file"
614 #ifdef HAVE_LIBUTIL_H
618 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
619 #define extattr_get_link extattr_get_file
621 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
622 #define extattr_set_link extattr_set_file
624 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
625 #define extattr_list_link extattr_list_file
628 #if defined(HAVE_FREEBSD_OS)
629 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
630 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
631 static const char *xattr_acl_skiplist[2] = { "system.posix1e.acl_access", NULL };
632 static const char *xattr_skiplist[1] = { NULL };
633 #elif defined(HAVE_NETBSD_OS)
634 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
635 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
636 static const char *xattr_acl_skiplist[1] = { NULL };
637 static const char *xattr_skiplist[1] = { NULL };
638 #elif defined(HAVE_OPENBSD_OS)
639 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
640 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
641 static const char *xattr_acl_skiplist[1] = { NULL };
642 static const char *xattr_skiplist[1] = { NULL };
645 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
649 int cnt, index, xattr_count = 0;
650 int32_t xattr_list_len,
652 uint32_t expected_serialize_len = 0;
653 unsigned int namespace_index;
655 char *current_attrnamespace = NULL;
656 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
657 xattr_t *current_xattr;
658 alist *xattr_value_list = NULL;
659 bxattr_exit_code retval = bxattr_exit_error;
662 xattr_value_list = New(alist(10, not_owned_by_alist));
665 * Loop over all available xattr namespaces.
667 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
668 attrnamespace = os_default_xattr_namespaces[namespace_index];
671 * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
672 * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
674 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
675 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
676 attrnamespace, jcr->last_fname);
677 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
678 attrnamespace, jcr->last_fname);
683 * First get the length of the available list with extended attributes.
684 * If we get EPERM on system namespace, don't return error.
685 * This is expected for normal users trying to archive the system
686 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
687 * they've decided to return EOPNOTSUPP instead.
689 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
690 if (xattr_list_len < 0) {
693 retval = bxattr_exit_ok;
695 #if defined(EOPNOTSUPP)
699 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
700 actuallyfree(current_attrnamespace);
701 current_attrnamespace = NULL;
708 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
709 jcr->last_fname, be.bstrerror());
710 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
711 jcr->last_fname, be.bstrerror());
714 } else if (xattr_list_len == 0) {
719 * Allocate room for the extented attribute list.
721 xattr_list = (char *)malloc(xattr_list_len + 1);
722 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
725 * Get the actual list of extended attributes names for a file.
727 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
728 if (xattr_list_len < 0) {
731 retval = bxattr_exit_ok;
734 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
735 jcr->last_fname, be.bstrerror());
736 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
737 jcr->last_fname, be.bstrerror());
741 xattr_list[xattr_list_len] = '\0';
744 * Walk the list of extended attributes names and retrieve the data.
745 * We already count the bytes needed for serializing the stream later on.
747 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
751 * Print the current name into the buffer as its not null terminated we need to
752 * use the length encoded in the string for copying only the needed bytes.
754 cnt = xattr_list[index];
755 if (cnt > ((int)sizeof(current_attrname) - 1)) {
756 cnt = ((int)sizeof(current_attrname) - 1);
758 strncpy(current_attrname, xattr_list + (index + 1), cnt);
759 current_attrname[cnt] = '\0';
762 * First make a xattr tuple of the current namespace and the name of the xattr.
763 * e.g. something like user.<attrname> or system.<attrname>
765 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
768 * On some OSes you also get the acls in the extented attribute list.
769 * So we check if we are already backing up acls and if we do we
770 * don't store the extended attribute with the same info.
772 if (ff_pkt->flags & FO_ACL) {
773 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
774 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
782 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
785 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
786 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
798 * Each xattr valuepair starts with a magic so we can parse it easier.
800 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
801 current_xattr->magic = XATTR_MAGIC;
802 expected_serialize_len += sizeof(current_xattr->magic);
805 * Allocate space for storing the name.
807 current_xattr->name_length = strlen(current_attrtuple);
808 current_xattr->name = (char *)malloc(current_xattr->name_length);
809 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
811 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
814 * First see how long the value is for the extended attribute.
816 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
817 if (xattr_value_len < 0) {
820 retval = bxattr_exit_ok;
821 free(current_xattr->name);
825 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
826 jcr->last_fname, be.bstrerror());
827 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
828 jcr->last_fname, be.bstrerror());
829 free(current_xattr->name);
836 * Allocate space for storing the value.
838 current_xattr->value = (char *)malloc(xattr_value_len);
839 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
841 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
842 if (xattr_value_len < 0) {
845 retval = bxattr_exit_ok;
846 free(current_xattr->value);
847 free(current_xattr->name);
851 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
852 jcr->last_fname, be.bstrerror());
853 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
854 jcr->last_fname, be.bstrerror());
855 free(current_xattr->value);
856 free(current_xattr->name);
863 * Store the actual length of the value.
865 current_xattr->value_length = xattr_value_len;
866 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
869 * Protect ourself against things getting out of hand.
871 if (expected_serialize_len >= MAX_XATTR_STREAM) {
872 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
873 jcr->last_fname, MAX_XATTR_STREAM);
874 free(current_xattr->value);
875 free(current_xattr->name);
880 xattr_value_list->append(current_xattr);
886 * Drop the local copy of the current_attrnamespace.
888 actuallyfree(current_attrnamespace);
889 current_attrnamespace = NULL;
892 * We are done with this xattr list.
895 xattr_list = (char *)NULL;
899 * If we found any xattr send them to the SD.
901 if (xattr_count > 0) {
903 * Serialize the datastream.
905 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
906 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
908 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
913 xattr_drop_internal_table(xattr_value_list);
914 xattr_value_list = NULL;
917 * Send the datastream to the SD.
919 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
921 xattr_drop_internal_table(xattr_value_list);
922 xattr_value_list = NULL;
924 return bxattr_exit_ok;
928 if (current_attrnamespace != NULL) {
929 actuallyfree(current_attrnamespace);
930 current_attrnamespace = NULL;
932 if (xattr_list != NULL) {
935 if (xattr_value_list != NULL) {
936 xattr_drop_internal_table(xattr_value_list);
937 xattr_value_list = NULL;
942 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
944 xattr_t *current_xattr;
945 alist *xattr_value_list;
946 int current_attrnamespace, cnt;
947 char *attrnamespace, *attrname;
950 xattr_value_list = New(alist(10, not_owned_by_alist));
952 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
953 xattr_drop_internal_table(xattr_value_list);
954 return bxattr_exit_error;
957 foreach_alist(current_xattr, xattr_value_list) {
959 * Try splitting the xattr_name into a namespace and name part.
960 * The splitting character is a .
962 attrnamespace = current_xattr->name;
963 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
964 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
965 current_xattr->name, jcr->last_fname);
966 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
967 current_xattr->name, jcr->last_fname);
973 * Make sure the attrnamespace makes sense.
975 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
976 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
977 attrnamespace, jcr->last_fname);
978 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
979 attrnamespace, jcr->last_fname);
984 * Try restoring the extended attribute.
986 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
987 attrname, current_xattr->value, current_xattr->value_length);
988 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
994 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
995 jcr->last_fname, be.bstrerror());
996 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
997 jcr->last_fname, be.bstrerror());
1004 xattr_drop_internal_table(xattr_value_list);
1005 return bxattr_exit_ok;
1008 xattr_drop_internal_table(xattr_value_list);
1009 return bxattr_exit_error;
1013 * Function pointers to the build and parse function to use for these xattrs.
1015 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1016 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1018 #elif defined(HAVE_SUN_OS)
1020 * Solaris extended attributes were introduced in Solaris 9
1023 * Solaris extensible attributes were introduced in OpenSolaris
1024 * by PSARC 2007/315 Solaris extensible attributes are also
1025 * sometimes called extended system attributes.
1027 * man fsattr(5) on Solaris gives a wealth of info. The most
1028 * important bits are:
1030 * Attributes are logically supported as files within the file
1031 * system. The file system is therefore augmented with an
1032 * orthogonal name space of file attributes. Any file (includ-
1033 * ing attribute files) can have an arbitrarily deep attribute
1034 * tree associated with it. Attribute values are accessed by
1035 * file descriptors obtained through a special attribute inter-
1036 * face. This logical view of "attributes as files" allows the
1037 * leveraging of existing file system interface functionality
1038 * to support the construction, deletion, and manipulation of
1041 * The special files "." and ".." retain their accustomed
1042 * semantics within the attribute hierarchy. The "." attribute
1043 * file refers to the current directory and the ".." attribute
1044 * file refers to the parent directory. The unnamed directory
1045 * at the head of each attribute tree is considered the "child"
1046 * of the file it is associated with and the ".." file refers
1047 * to the associated file. For any non-directory file with
1048 * attributes, the ".." entry in the unnamed directory refers
1049 * to a file that is not a directory.
1051 * Conceptually, the attribute model is fully general. Extended
1052 * attributes can be any type of file (doors, links, direc-
1053 * tories, and so forth) and can even have their own attributes
1054 * (fully recursive). As a result, the attributes associated
1055 * with a file could be an arbitrarily deep directory hierarchy
1056 * where each attribute could have an equally complex attribute
1057 * tree associated with it. Not all implementations are able
1058 * to, or want to, support the full model. Implementation are
1059 * therefore permitted to reject operations that are not sup-
1060 * ported. For example, the implementation for the UFS file
1061 * system allows only regular files as attributes (for example,
1062 * no sub-directories) and rejects attempts to place attributes
1065 * The following list details the operations that are rejected
1066 * in the current implementation:
1068 * link Any attempt to create links between
1069 * attribute and non-attribute space
1070 * is rejected to prevent security-
1071 * related or otherwise sensitive
1072 * attributes from being exposed, and
1073 * therefore manipulable, as regular
1076 * rename Any attempt to rename between
1077 * attribute and non-attribute space
1078 * is rejected to prevent an already
1079 * linked file from being renamed and
1080 * thereby circumventing the link res-
1083 * mkdir, symlink, mknod Any attempt to create a "non-
1084 * regular" file in attribute space is
1085 * rejected to reduce the functional-
1086 * ity, and therefore exposure and
1087 * risk, of the initial implementa-
1090 * The entire available name space has been allocated to "gen-
1091 * eral use" to bring the implementation in line with the NFSv4
1092 * draft standard [NFSv4]. That standard defines "named attri-
1093 * butes" (equivalent to Solaris Extended Attributes) with no
1094 * naming restrictions. All Sun applications making use of
1095 * opaque extended attributes will use the prefix "SUNW".
1098 #ifdef HAVE_SYS_ATTR_H
1099 #include <sys/attr.h>
1106 #ifdef HAVE_SYS_NVPAIR_H
1107 #include <sys/nvpair.h>
1110 #ifdef HAVE_SYS_ACL_H
1111 #include <sys/acl.h>
1114 #if !defined(HAVE_OPENAT) || \
1115 !defined(HAVE_UNLINKAT) || \
1116 !defined(HAVE_FCHOWNAT) || \
1117 !defined(HAVE_FUTIMESAT)
1118 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
1122 * Define the supported XATTR streams for this OS
1124 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1125 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
1127 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
1128 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
1131 * This code creates a temporary cache with entries for each xattr which has
1132 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
1134 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
1136 xattr_link_cache_entry_t *ptr;
1138 foreach_alist(ptr, jcr->xattr_data->link_cache) {
1139 if (ptr && ptr->inum == inum) {
1146 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
1148 xattr_link_cache_entry_t *ptr;
1150 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
1151 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
1153 bstrncpy(ptr->target, target, sizeof(ptr->target));
1154 jcr->xattr_data->link_cache->append(ptr);
1157 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1159 * This function returns true if a non default extended system attribute
1160 * list is associated with fd and returns false when an error has occured
1161 * or when only extended system attributes other than archive,
1162 * av_modified or crtime are set.
1164 * The function returns true for the following cases:
1166 * - any extended system attribute other than the default attributes
1167 * ('archive', 'av_modified' and 'crtime') is set
1168 * - nvlist has NULL name string
1169 * - nvpair has data type of 'nvlist'
1170 * - default data type.
1172 static bool solaris_has_non_transient_extensible_attributes(int fd)
1180 bool retval = false;
1182 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
1187 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
1188 name = nvpair_name(pair);
1191 fattr = name_to_attr(name);
1197 type = nvpair_type(pair);
1199 case DATA_TYPE_BOOLEAN_VALUE:
1200 if (nvpair_value_boolean_value(pair, &value) != 0) {
1203 if (value && fattr != F_ARCHIVE &&
1204 fattr != F_AV_MODIFIED) {
1209 case DATA_TYPE_UINT64_ARRAY:
1210 if (fattr != F_CRTIME) {
1215 case DATA_TYPE_NVLIST:
1223 if (response != NULL) {
1224 nvlist_free(response);
1228 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1230 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
1232 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1233 * There is no need to store those acls as we already store the stat bits too.
1235 static bool acl_is_trivial(int count, aclent_t *entries)
1240 for (n = 0; n < count; n++) {
1242 if (!(ace->a_type == USER_OBJ ||
1243 ace->a_type == GROUP_OBJ ||
1244 ace->a_type == OTHER_OBJ ||
1245 ace->a_type == CLASS_OBJ))
1250 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
1252 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
1255 #ifdef HAVE_EXTENDED_ACL
1261 * See if this attribute has an ACL
1263 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
1264 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
1266 * See if there is a non trivial acl on the file.
1268 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
1269 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
1272 return bxattr_exit_ok;
1274 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1275 attrname, jcr->last_fname, be.bstrerror());
1276 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
1277 attrname, jcr->last_fname, be.bstrerror());
1278 return bxattr_exit_error;
1283 #if defined(ACL_SID_FMT)
1285 * New format flag added in newer Solaris versions.
1287 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1289 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1290 #endif /* ACL_SID_FMT */
1292 *acl_text = acl_totext(aclp, flags);
1300 return bxattr_exit_ok;
1301 #else /* HAVE_EXTENDED_ACL */
1303 aclent_t *acls = NULL;
1307 * See if this attribute has an ACL
1310 n = facl(fd, GETACLCNT, 0, NULL);
1312 n = acl(attrname, GETACLCNT, 0, NULL);
1315 if (n >= MIN_ACL_ENTRIES) {
1316 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1317 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
1318 acl(attrname, GETACL, n, acls) != n) {
1322 return bxattr_exit_ok;
1324 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1325 attrname, jcr->last_fname, be.bstrerror());
1326 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
1327 attrname, jcr->last_fname, be.bstrerror());
1329 return bxattr_exit_error;
1334 * See if there is a non trivial acl on the file.
1336 if (!acl_is_trivial(n, acls)) {
1337 if ((*acl_text = acltotext(acls, n)) == NULL) {
1338 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
1339 attrname, jcr->last_fname, be.bstrerror());
1340 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
1341 attrname, jcr->last_fname, be.bstrerror());
1343 return bxattr_exit_error;
1353 return bxattr_exit_ok;
1354 #endif /* HAVE_EXTENDED_ACL */
1356 #else /* HAVE_ACL */
1357 return bxattr_exit_ok;
1358 #endif /* HAVE_ACL */
1362 * Forward declaration for recursive function call.
1364 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
1367 * Save an extended or extensible attribute.
1368 * This is stored as an opaque stream of bytes with the following encoding:
1370 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
1372 * or for a hardlinked or symlinked attribute
1374 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
1376 * xattr_name can be a subpath relative to the file the xattr is on.
1377 * stat_buffer is the string representation of the stat struct.
1378 * acl_string is an acl text when a non trivial acl is set on the xattr.
1379 * actual_xattr_data is the content of the xattr file.
1381 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
1382 const char *attrname, bool toplevel_hidden_dir, int stream)
1387 xattr_link_cache_entry_t *xlce;
1388 char target_attrname[PATH_MAX];
1389 char link_source[PATH_MAX];
1390 char *acl_text = NULL;
1391 char attribs[MAXSTRING];
1392 char buffer[XATTR_BUFSIZ];
1393 bxattr_exit_code retval = bxattr_exit_error;
1396 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
1399 * Get the stats of the extended or extensible attribute.
1401 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
1404 retval = bxattr_exit_ok;
1407 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
1408 target_attrname, jcr->last_fname, be.bstrerror());
1409 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
1410 target_attrname, jcr->last_fname, be.bstrerror());
1416 * Based on the filetype perform the correct action. We support most filetypes here, more
1417 * then the actual implementation on Solaris supports so some code may never get executed
1418 * due to limitations in the implementation.
1420 switch (st.st_mode & S_IFMT) {
1425 * Get any acl on the xattr.
1427 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1431 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1432 * Encode the stat struct into an ASCII representation.
1434 encode_stat(attribs, &st, 0, stream);
1435 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
1436 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1440 * Get any acl on the xattr.
1442 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1446 * See if this is the toplevel_hidden_dir being saved.
1448 if (toplevel_hidden_dir) {
1450 * Save the data for later storage when we encounter a real xattr. We store the data
1451 * in the jcr->xattr_data->content buffer and flush that just before sending out the
1452 * first real xattr. Encode the stat struct into an ASCII representation and jump
1453 * out of the function.
1455 encode_stat(attribs, &st, 0, stream);
1456 cnt = bsnprintf(buffer, sizeof(buffer),
1458 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1459 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1460 jcr->xattr_data->content_length = cnt;
1464 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1465 * Encode the stat struct into an ASCII representation.
1467 encode_stat(attribs, &st, 0, stream);
1468 cnt = bsnprintf(buffer, sizeof(buffer),
1470 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1475 * If this is a hardlinked file check the inode cache for a hit.
1477 if (st.st_nlink > 1) {
1479 * See if the cache already knows this inode number.
1481 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
1483 * Generate a xattr encoding with the reference to the target in there.
1485 encode_stat(attribs, &st, st.st_ino, stream);
1486 cnt = bsnprintf(buffer, sizeof(buffer),
1488 target_attrname, 0, attribs, 0, xlce->target, 0);
1489 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1490 jcr->xattr_data->content_length = cnt;
1491 retval = send_xattr_stream(jcr, stream);
1494 * For a hard linked file we are ready now, no need to recursively save the attributes.
1500 * Store this hard linked file in the cache.
1501 * Store the name relative to the top level xattr space.
1503 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
1507 * Get any acl on the xattr.
1509 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
1514 * Encode the stat struct into an ASCII representation.
1516 encode_stat(attribs, &st, 0, stream);
1517 cnt = bsnprintf(buffer, sizeof(buffer),
1519 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1522 * Open the extended or extensible attribute file.
1524 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1527 retval = bxattr_exit_ok;
1530 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1531 target_attrname, jcr->last_fname, be.bstrerror());
1532 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1533 target_attrname, jcr->last_fname, be.bstrerror());
1540 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1541 * Encode the stat struct into an ASCII representation.
1543 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1546 retval = bxattr_exit_ok;
1549 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1550 target_attrname, jcr->last_fname, be.bstrerror());
1551 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1552 target_attrname, jcr->last_fname, be.bstrerror());
1558 * Generate a xattr encoding with the reference to the target in there.
1560 encode_stat(attribs, &st, st.st_ino, stream);
1561 cnt = bsnprintf(buffer, sizeof(buffer),
1563 target_attrname, 0, attribs, 0, link_source, 0);
1564 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1565 jcr->xattr_data->content_length = cnt;
1566 retval = send_xattr_stream(jcr, stream);
1568 if (retval == bxattr_exit_ok) {
1569 jcr->xattr_data->nr_saved++;
1573 * For a soft linked file we are ready now, no need to recursively save the attributes.
1581 * See if this is the first real xattr being saved.
1582 * If it is save the toplevel_hidden_dir attributes first.
1583 * This is easy as its stored already in the jcr->xattr_data->content buffer.
1585 if (jcr->xattr_data->nr_saved == 0) {
1586 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1587 if (retval != bxattr_exit_ok) {
1590 jcr->xattr_data->nr_saved++;
1593 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1594 jcr->xattr_data->content_length = cnt;
1597 * Only dump the content of regular files.
1599 switch (st.st_mode & S_IFMT) {
1601 if (st.st_size > 0) {
1603 * Protect ourself against things getting out of hand.
1605 if (st.st_size >= MAX_XATTR_STREAM) {
1606 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1607 jcr->last_fname, MAX_XATTR_STREAM);
1611 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1612 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
1613 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
1614 jcr->xattr_data->content_length += cnt;
1618 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
1619 target_attrname, jcr->last_fname);
1620 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1621 target_attrname, jcr->last_fname);
1632 retval = send_xattr_stream(jcr, stream);
1633 if (retval == bxattr_exit_ok) {
1634 jcr->xattr_data->nr_saved++;
1639 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1640 * available on this extended attribute.
1643 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1646 * The recursive call could change our working dir so change back to the wanted workdir.
1648 if (fchdir(fd) < 0) {
1651 retval = bxattr_exit_ok;
1654 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1655 jcr->last_fname, be.bstrerror());
1656 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1657 jcr->last_fname, fd, be.bstrerror());
1664 if (acl_text != NULL) {
1673 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1676 int fd, filefd = -1, attrdirfd = -1;
1679 char current_xattr_namespace[PATH_MAX];
1680 bxattr_exit_code retval = bxattr_exit_error;
1684 * Determine what argument to use. Use attr_parent when set
1685 * (recursive call) or jcr->last_fname for first call. Also save
1686 * the current depth of the xattr_space we are in.
1690 if (xattr_namespace) {
1691 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1692 xattr_namespace, attr_parent);
1694 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1697 name = jcr->last_fname;
1698 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1702 * Open the file on which to save the xattrs read-only.
1704 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1707 retval = bxattr_exit_ok;
1710 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1711 jcr->last_fname, be.bstrerror());
1712 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1713 jcr->last_fname, be.bstrerror());
1719 * Open the xattr naming space.
1721 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1725 * Gentile way of the system saying this type of xattr layering is not supported.
1726 * Which is not problem we just forget about this this xattr.
1727 * But as this is not an error we return a positive return value.
1729 retval = bxattr_exit_ok;
1732 retval = bxattr_exit_ok;
1735 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1736 name, jcr->last_fname, be.bstrerror());
1737 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1738 name, jcr->last_fname, be.bstrerror());
1744 * We need to change into the attribute directory to determine if each of the
1745 * attributes should be saved.
1747 if (fchdir(attrdirfd) < 0) {
1748 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1749 jcr->last_fname, be.bstrerror());
1750 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1751 jcr->last_fname, attrdirfd, be.bstrerror());
1756 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1757 * else because the readdir returns "." entry after the extensible attr entry.
1758 * And as we want this entry before anything else we better just save its data.
1761 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1762 true, STREAM_XATTR_SOLARIS);
1764 if ((fd = dup(attrdirfd)) == -1 ||
1765 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1766 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1767 jcr->last_fname, be.bstrerror());
1768 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1769 jcr->last_fname, fd, be.bstrerror());
1775 * Walk the namespace.
1777 while (dp = readdir(dirp)) {
1779 * Skip only the toplevel . dir.
1781 if (!attr_parent && bstrcmp(dp->d_name, "."))
1785 * Skip all .. directories
1787 if (bstrcmp(dp->d_name, ".."))
1790 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1791 current_xattr_namespace, dp->d_name, jcr->last_fname);
1793 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1795 * We are not interested in read-only extensible attributes.
1797 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
1798 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1799 current_xattr_namespace, dp->d_name, jcr->last_fname);
1805 * We are only interested in read-write extensible attributes
1806 * when they contain non-transient values.
1808 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
1810 * Determine if there are non-transient system attributes at the toplevel.
1811 * We need to provide a fd to the open file.
1813 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1814 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1815 current_xattr_namespace, dp->d_name, jcr->last_fname);
1822 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1823 false, STREAM_XATTR_SOLARIS_SYS);
1826 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1831 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1832 false, STREAM_XATTR_SOLARIS);
1836 retval = bxattr_exit_ok;
1839 if (attrdirfd != -1)
1847 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1849 #ifdef HAVE_EXTENDED_ACL
1854 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1855 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
1857 return bxattr_exit_error;
1860 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1861 acl_set(attrname, aclp) != 0) {
1862 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1863 attrname, jcr->last_fname, be.bstrerror());
1864 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1865 attrname, jcr->last_fname, be.bstrerror());
1866 return bxattr_exit_error;
1872 return bxattr_exit_ok;
1874 #else /* HAVE_EXTENDED_ACL */
1876 aclent_t *acls = NULL;
1879 acls = aclfromtext(acl_text, &n);
1881 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1882 acl(attrname, SETACL, n, acls) != 0) {
1883 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1884 attrname, jcr->last_fname, be.bstrerror());
1885 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1886 attrname, jcr->last_fname, be.bstrerror());
1887 return bxattr_exit_error;
1894 return bxattr_exit_ok;
1896 #endif /* HAVE_EXTENDED_ACL */
1899 #endif /* HAVE_ACL */
1901 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1903 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1904 int used_bytes, total_bytes, cnt;
1905 char *bp, *target_attrname, *attribs;
1906 char *linked_target = NULL;
1907 char *acl_text = NULL;
1911 struct timeval times[2];
1912 bxattr_exit_code retval = bxattr_exit_error;
1916 * Parse the xattr stream. First the part that is the same for all xattrs.
1919 total_bytes = jcr->xattr_data->content_length;
1922 * The name of the target xattr has a leading / we are not interested
1923 * in that so skip it when decoding the string. We always start a the /
1924 * of the xattr space anyway.
1926 target_attrname = jcr->xattr_data->content + 1;
1927 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1928 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1934 * Open the file on which to restore the xattrs read-only.
1936 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1937 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1938 jcr->last_fname, be.bstrerror());
1939 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1940 jcr->last_fname, be.bstrerror());
1945 * Open the xattr naming space and make it the current working dir.
1947 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1948 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1949 jcr->last_fname, be.bstrerror());
1950 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1951 jcr->last_fname, be.bstrerror());
1955 if (fchdir(attrdirfd) < 0) {
1956 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1957 jcr->last_fname, be.bstrerror());
1958 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1959 jcr->last_fname, attrdirfd, be.bstrerror());
1964 * Try to open the correct xattr subdir based on the target_attrname given.
1965 * e.g. check if its a subdir attrname. Each / in the string makes us go
1968 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1971 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1972 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1973 target_attrname, jcr->last_fname, be.bstrerror());
1974 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1975 target_attrname, jcr->last_fname, be.bstrerror());
1983 * Open the xattr naming space.
1985 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1986 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1987 target_attrname, jcr->last_fname, be.bstrerror());
1988 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1989 target_attrname, jcr->last_fname, be.bstrerror());
1997 * Make the xattr space our current workingdir.
1999 if (fchdir(attrdirfd) < 0) {
2000 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2001 target_attrname, jcr->last_fname, be.bstrerror());
2002 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2003 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2007 target_attrname = ++bp;
2011 * Decode the attributes from the stream.
2013 decode_stat(attribs, &st, &inum);
2016 * Decode the next field (acl_text).
2018 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2019 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2025 * Based on the filetype perform the correct action. We support most filetypes here, more
2026 * then the actual implementation on Solaris supports so some code may never get executed
2027 * due to limitations in the implementation.
2029 switch (st.st_mode & S_IFMT) {
2032 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2034 unlinkat(attrdirfd, target_attrname, 0);
2035 if (mkfifo(target_attrname, st.st_mode) < 0) {
2036 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
2037 target_attrname, jcr->last_fname, be.bstrerror());
2038 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
2039 target_attrname, jcr->last_fname, be.bstrerror());
2046 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2048 unlinkat(attrdirfd, target_attrname, 0);
2049 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
2050 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
2051 target_attrname, jcr->last_fname, be.bstrerror());
2052 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
2053 target_attrname, jcr->last_fname, be.bstrerror());
2059 * If its not the hidden_dir create the entry.
2060 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2062 if (!bstrcmp(target_attrname, ".")) {
2063 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
2064 if (mkdir(target_attrname, st.st_mode) < 0) {
2065 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
2066 target_attrname, jcr->last_fname, be.bstrerror());
2067 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
2068 target_attrname, jcr->last_fname, be.bstrerror());
2075 * See if this is a hard linked file. e.g. inum != 0
2080 unlinkat(attrdirfd, target_attrname, 0);
2081 if (link(linked_target, target_attrname) < 0) {
2082 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
2083 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2084 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
2085 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2090 * Successfully restored xattr.
2092 retval = bxattr_exit_ok;
2095 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
2096 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
2100 if (used_bytes < (total_bytes - 1))
2104 * Restore the actual xattr.
2106 if (!is_extensible) {
2107 unlinkat(attrdirfd, target_attrname, 0);
2110 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
2111 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2112 target_attrname, jcr->last_fname, be.bstrerror());
2113 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2114 target_attrname, jcr->last_fname, be.bstrerror());
2120 * Restore the actual data.
2122 if (st.st_size > 0) {
2123 used_bytes = (data - jcr->xattr_data->content);
2124 cnt = total_bytes - used_bytes;
2127 * Do a sanity check, the st.st_size should be the same as the number of bytes
2128 * we have available as data of the stream.
2130 if (cnt != st.st_size) {
2131 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
2132 target_attrname, jcr->last_fname);
2133 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
2134 target_attrname, jcr->last_fname);
2139 cnt = write(attrfd, data, cnt);
2141 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
2142 target_attrname, jcr->last_fname, be.bstrerror());
2143 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
2144 target_attrname, jcr->last_fname, be.bstrerror());
2150 cnt = total_bytes - used_bytes;
2156 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2160 if (symlink(linked_target, target_attrname) < 0) {
2161 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
2162 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2163 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
2164 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2169 * Successfully restored xattr.
2171 retval = bxattr_exit_ok;
2178 * Restore owner and acl for non extensible attributes.
2180 if (!is_extensible) {
2181 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
2185 * Gentile way of the system saying this type of xattr layering is not supported.
2186 * But as this is not an error we return a positive return value.
2188 retval = bxattr_exit_ok;
2191 retval = bxattr_exit_ok;
2194 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
2195 target_attrname, jcr->last_fname, be.bstrerror());
2196 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
2197 target_attrname, jcr->last_fname, be.bstrerror());
2204 if (acl_text && *acl_text)
2205 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
2207 #endif /* HAVE_ACL */
2210 * For a non extensible attribute restore access and modification time on the xattr.
2212 if (!is_extensible) {
2213 times[0].tv_sec = st.st_atime;
2214 times[0].tv_usec = 0;
2215 times[1].tv_sec = st.st_mtime;
2216 times[1].tv_usec = 0;
2218 if (futimesat(attrdirfd, target_attrname, times) < 0) {
2219 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
2220 target_attrname, jcr->last_fname, be.bstrerror());
2221 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
2222 target_attrname, jcr->last_fname, be.bstrerror());
2228 * Successfully restored xattr.
2230 retval = bxattr_exit_ok;
2234 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
2236 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
2243 if (attrdirfd != -1) {
2252 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2255 bxattr_exit_code retval = bxattr_exit_ok;
2258 * First see if extended attributes or extensible attributes are present.
2259 * If not just pretend things went ok.
2261 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
2262 jcr->xattr_data->nr_saved = 0;
2263 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
2266 * As we change the cwd in the save function save the current cwd
2267 * for restore after return from the solaris_save_xattrs function.
2269 getcwd(cwd, sizeof(cwd));
2270 retval = solaris_save_xattrs(jcr, NULL, NULL);
2272 delete jcr->xattr_data->link_cache;
2273 jcr->xattr_data->link_cache = NULL;
2278 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
2281 bool is_extensible = false;
2282 bxattr_exit_code retval;
2285 * First make sure we can restore xattr on the filesystem.
2288 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2289 case STREAM_XATTR_SOLARIS_SYS:
2290 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
2291 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
2292 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
2294 return bxattr_exit_error;
2297 is_extensible = true;
2300 case STREAM_XATTR_SOLARIS:
2301 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
2302 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
2303 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
2305 return bxattr_exit_error;
2309 return bxattr_exit_error;
2313 * As we change the cwd in the restore function save the current cwd
2314 * for restore after return from the solaris_restore_xattrs function.
2316 getcwd(cwd, sizeof(cwd));
2317 retval = solaris_restore_xattrs(jcr, is_extensible);
2324 * Function pointers to the build and parse function to use for these xattrs.
2326 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
2327 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
2329 #endif /* defined(HAVE_SUN_OS) */
2332 * Entry points when compiled with support for XATTRs on a supported platform.
2334 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2336 if (os_build_xattr_streams) {
2337 return (*os_build_xattr_streams)(jcr, ff_pkt);
2339 return bxattr_exit_error;
2342 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
2346 if (os_parse_xattr_streams) {
2348 * See if we can parse this stream, and ifso give it a try.
2350 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
2351 if (os_default_xattr_streams[cnt] == stream) {
2352 return (*os_parse_xattr_streams)(jcr, stream);
2357 * Issue a warning and discard the message. But pretend the restore was ok.
2359 Jmsg2(jcr, M_WARNING, 0,
2360 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
2361 jcr->last_fname, stream);
2362 return bxattr_exit_error;