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 * - 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 if (current_xattr->value_length > 0 && current_xattr->value) {
197 ser_bytes(current_xattr->value, current_xattr->value_length);
201 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
202 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
204 return jcr->xattr_data->content_length;
207 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
210 xattr_t *current_xattr;
213 * Parse the stream and call restore_xattr_on_file for each extended attribute.
215 * Start unserializing the data. We keep on looping while we have not
216 * unserialized all bytes in the stream.
218 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
219 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
221 * First make sure the magic is present. This way we can easily catch corruption.
222 * Any missing MAGIC is fatal we do NOT try to continue.
225 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
226 unser_uint32(current_xattr->magic);
227 if (current_xattr->magic != XATTR_MAGIC) {
228 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
230 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
233 return bxattr_exit_error;
237 * Decode the valuepair. First decode the length of the name.
239 unser_uint32(current_xattr->name_length);
240 if (current_xattr->name_length == 0) {
241 Mmsg1(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
243 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
246 return bxattr_exit_error;
250 * Allocate room for the name and decode its content.
252 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
253 unser_bytes(current_xattr->name, current_xattr->name_length);
256 * The xattr_name needs to be null terminated for lsetxattr.
258 current_xattr->name[current_xattr->name_length] = '\0';
261 * Decode the value length.
263 unser_uint32(current_xattr->value_length);
265 if (current_xattr->value_length > 0) {
267 * Allocate room for the value and decode its content.
269 current_xattr->value = (char *)malloc(current_xattr->value_length);
270 unser_bytes(current_xattr->value, current_xattr->value_length);
272 current_xattr->value = NULL;
275 xattr_value_list->append(current_xattr);
278 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
279 return bxattr_exit_ok;
284 * This is a supported OS, See what kind of interface we should use.
286 #if defined(HAVE_DARWIN_OS) || \
287 defined(HAVE_LINUX_OS)
289 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
290 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
291 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
292 #error "Missing either full support for the LXATTR or XATTR functions."
295 #ifdef HAVE_SYS_XATTR_H
296 #include <sys/xattr.h>
298 #error "Missing sys/xattr.h header file"
302 * Define the supported XATTR streams for this OS
304 #if defined(HAVE_DARWIN_OS)
305 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
306 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
307 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
308 #elif defined(HAVE_LINUX_OS)
309 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
310 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
311 static const char *xattr_skiplist[1] = { NULL };
315 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
316 * listxattr, getxattr and setxattr with an extra options argument
317 * which mimics the l variants of the functions when we specify
318 * XATTR_NOFOLLOW as the options value.
320 #if defined(HAVE_DARWIN_OS)
321 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
322 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
323 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
326 * Fallback to the non l-functions when those are not available.
328 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
329 #define lgetxattr getxattr
331 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
332 #define lsetxattr setxattr
334 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
335 #define llistxattr listxattr
339 static bxattr_exit_code linux_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
342 char *xattr_list, *bp;
343 int cnt, xattr_count = 0;
344 int32_t xattr_list_len,
346 uint32_t expected_serialize_len = 0;
347 xattr_t *current_xattr;
348 alist *xattr_value_list = NULL;
349 bxattr_exit_code retval = bxattr_exit_error;
353 * First get the length of the available list with extended attributes.
355 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
356 switch (xattr_list_len) {
360 return bxattr_exit_ok;
362 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
363 jcr->last_fname, be.bstrerror());
364 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
365 jcr->last_fname, be.bstrerror());
366 return bxattr_exit_error;
370 return bxattr_exit_ok;
376 * Allocate room for the extented attribute list.
378 xattr_list = (char *)malloc(xattr_list_len + 1);
379 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
382 * Get the actual list of extended attributes names for a file.
384 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
385 switch (xattr_list_len) {
389 retval = bxattr_exit_ok;
392 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
393 jcr->last_fname, be.bstrerror());
394 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
395 jcr->last_fname, be.bstrerror());
402 xattr_list[xattr_list_len] = '\0';
404 xattr_value_list = New(alist(10, not_owned_by_alist));
407 * Walk the list of extended attributes names and retrieve the data.
408 * We already count the bytes needed for serializing the stream later on.
411 while ((bp - xattr_list) + 1 < xattr_list_len) {
416 * On some OSes you also get the acls in the extented attribute list.
417 * So we check if we are already backing up acls and if we do we
418 * don't store the extended attribute with the same info.
420 if (ff_pkt->flags & FO_ACL) {
421 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
422 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
430 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
433 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
434 if (bstrcmp(bp, xattr_skiplist[cnt])) {
441 name_len = strlen(bp);
442 if (skip_xattr || name_len == 0) {
443 bp = strchr(bp, '\0') + 1;
448 * Each xattr valuepair starts with a magic so we can parse it easier.
450 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
451 current_xattr->magic = XATTR_MAGIC;
452 expected_serialize_len += sizeof(current_xattr->magic);
455 * Allocate space for storing the name.
457 current_xattr->name_length = name_len;
458 current_xattr->name = (char *)malloc(current_xattr->name_length);
459 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
461 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
464 * First see how long the value is for the extended attribute.
466 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
467 switch (xattr_value_len) {
471 retval = bxattr_exit_ok;
472 free(current_xattr->name);
476 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
477 jcr->last_fname, be.bstrerror());
478 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
479 jcr->last_fname, be.bstrerror());
480 free(current_xattr->name);
486 current_xattr->value = NULL;
487 current_xattr->value_length = 0;
488 expected_serialize_len += sizeof(current_xattr->value_length);
492 * Allocate space for storing the value.
494 current_xattr->value = (char *)malloc(xattr_value_len);
495 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
497 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
498 if (xattr_value_len < 0) {
501 retval = bxattr_exit_ok;
502 free(current_xattr->value);
503 free(current_xattr->name);
507 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
508 jcr->last_fname, be.bstrerror());
509 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
510 jcr->last_fname, be.bstrerror());
511 free(current_xattr->value);
512 free(current_xattr->name);
518 * Store the actual length of the value.
520 current_xattr->value_length = xattr_value_len;
521 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
524 * Protect ourself against things getting out of hand.
526 if (expected_serialize_len >= MAX_XATTR_STREAM) {
527 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
528 jcr->last_fname, MAX_XATTR_STREAM);
529 free(current_xattr->value);
530 free(current_xattr->name);
537 xattr_value_list->append(current_xattr);
539 bp = strchr(bp, '\0') + 1;
543 xattr_list = (char *)NULL;
546 * If we found any xattr send them to the SD.
548 if (xattr_count > 0) {
550 * Serialize the datastream.
552 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
553 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
555 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
560 xattr_drop_internal_table(xattr_value_list);
563 * Send the datastream to the SD.
565 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
567 xattr_drop_internal_table(xattr_value_list);
569 return bxattr_exit_ok;
573 if (xattr_list != NULL) {
576 if (xattr_value_list != NULL) {
577 xattr_drop_internal_table(xattr_value_list);
582 static bxattr_exit_code linux_xattr_parse_streams(JCR *jcr, int stream)
584 xattr_t *current_xattr;
585 alist *xattr_value_list;
588 xattr_value_list = New(alist(10, not_owned_by_alist));
590 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
591 xattr_drop_internal_table(xattr_value_list);
592 return bxattr_exit_error;
595 foreach_alist(current_xattr, xattr_value_list) {
596 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
601 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
602 jcr->last_fname, be.bstrerror());
603 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
604 jcr->last_fname, be.bstrerror());
610 xattr_drop_internal_table(xattr_value_list);
611 return bxattr_exit_ok;
614 xattr_drop_internal_table(xattr_value_list);
615 return bxattr_exit_error;
619 * Function pointers to the build and parse function to use for these xattrs.
621 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = linux_xattr_build_streams;
622 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = linux_xattr_parse_streams;
624 #elif defined(HAVE_FREEBSD_OS) || \
625 defined(HAVE_NETBSD_OS) || \
626 defined(HAVE_OPENBSD_OS)
628 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
629 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
630 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
631 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
632 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
633 #error "Missing full support for the extattr functions."
636 #ifdef HAVE_SYS_EXTATTR_H
637 #include <sys/extattr.h>
639 #error "Missing sys/extattr.h header file"
642 #ifdef HAVE_LIBUTIL_H
646 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
647 #define extattr_get_link extattr_get_file
649 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
650 #define extattr_set_link extattr_set_file
652 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
653 #define extattr_list_link extattr_list_file
656 #if defined(HAVE_FREEBSD_OS)
657 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
658 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
659 static const char *xattr_acl_skiplist[2] = { "system.posix1e.acl_access", NULL };
660 static const char *xattr_skiplist[1] = { NULL };
661 #elif defined(HAVE_NETBSD_OS)
662 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
663 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
664 static const char *xattr_acl_skiplist[1] = { NULL };
665 static const char *xattr_skiplist[1] = { NULL };
666 #elif defined(HAVE_OPENBSD_OS)
667 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
668 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
669 static const char *xattr_acl_skiplist[1] = { NULL };
670 static const char *xattr_skiplist[1] = { NULL };
673 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
677 int cnt, index, xattr_count = 0;
678 int32_t xattr_list_len,
680 uint32_t expected_serialize_len = 0;
681 unsigned int namespace_index;
683 char *current_attrnamespace = NULL;
684 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
685 xattr_t *current_xattr;
686 alist *xattr_value_list = NULL;
687 bxattr_exit_code retval = bxattr_exit_error;
690 xattr_value_list = New(alist(10, not_owned_by_alist));
693 * Loop over all available xattr namespaces.
695 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
696 attrnamespace = os_default_xattr_namespaces[namespace_index];
699 * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
700 * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
702 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
703 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
704 attrnamespace, jcr->last_fname);
705 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
706 attrnamespace, jcr->last_fname);
711 * First get the length of the available list with extended attributes.
712 * If we get EPERM on system namespace, don't return error.
713 * This is expected for normal users trying to archive the system
714 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
715 * they've decided to return EOPNOTSUPP instead.
717 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
718 switch (xattr_list_len) {
722 retval = bxattr_exit_ok;
724 #if defined(EOPNOTSUPP)
728 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
729 actuallyfree(current_attrnamespace);
730 current_attrnamespace = NULL;
737 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
738 jcr->last_fname, be.bstrerror());
739 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
740 jcr->last_fname, be.bstrerror());
751 * Allocate room for the extented attribute list.
753 xattr_list = (char *)malloc(xattr_list_len + 1);
754 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
757 * Get the actual list of extended attributes names for a file.
759 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
760 switch (xattr_list_len) {
764 retval = bxattr_exit_ok;
767 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
768 jcr->last_fname, be.bstrerror());
769 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
770 jcr->last_fname, be.bstrerror());
777 xattr_list[xattr_list_len] = '\0';
780 * Walk the list of extended attributes names and retrieve the data.
781 * We already count the bytes needed for serializing the stream later on.
783 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
787 * Print the current name into the buffer as its not null terminated we need to
788 * use the length encoded in the string for copying only the needed bytes.
790 cnt = xattr_list[index];
791 if (cnt > ((int)sizeof(current_attrname) - 1)) {
792 cnt = ((int)sizeof(current_attrname) - 1);
794 strncpy(current_attrname, xattr_list + (index + 1), cnt);
795 current_attrname[cnt] = '\0';
798 * First make a xattr tuple of the current namespace and the name of the xattr.
799 * e.g. something like user.<attrname> or system.<attrname>
801 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
804 * On some OSes you also get the acls in the extented attribute list.
805 * So we check if we are already backing up acls and if we do we
806 * don't store the extended attribute with the same info.
808 if (ff_pkt->flags & FO_ACL) {
809 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
810 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
818 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
821 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
822 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
834 * Each xattr valuepair starts with a magic so we can parse it easier.
836 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
837 current_xattr->magic = XATTR_MAGIC;
838 expected_serialize_len += sizeof(current_xattr->magic);
841 * Allocate space for storing the name.
843 current_xattr->name_length = strlen(current_attrtuple);
844 current_xattr->name = (char *)malloc(current_xattr->name_length);
845 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
847 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
850 * First see how long the value is for the extended attribute.
852 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
853 switch (xattr_value_len) {
857 retval = bxattr_exit_ok;
858 free(current_xattr->name);
862 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
863 jcr->last_fname, be.bstrerror());
864 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
865 jcr->last_fname, be.bstrerror());
866 free(current_xattr->name);
872 current_xattr->value = NULL;
873 current_xattr->value_length = 0;
874 expected_serialize_len += sizeof(current_xattr->value_length);
878 * Allocate space for storing the value.
880 current_xattr->value = (char *)malloc(xattr_value_len);
881 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
883 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
884 if (xattr_value_len < 0) {
887 retval = bxattr_exit_ok;
888 free(current_xattr->value);
889 free(current_xattr->name);
893 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
894 jcr->last_fname, be.bstrerror());
895 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
896 jcr->last_fname, be.bstrerror());
897 free(current_xattr->value);
898 free(current_xattr->name);
905 * Store the actual length of the value.
907 current_xattr->value_length = xattr_value_len;
908 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
911 * Protect ourself against things getting out of hand.
913 if (expected_serialize_len >= MAX_XATTR_STREAM) {
914 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
915 jcr->last_fname, MAX_XATTR_STREAM);
916 free(current_xattr->value);
917 free(current_xattr->name);
924 xattr_value_list->append(current_xattr);
930 * Drop the local copy of the current_attrnamespace.
932 actuallyfree(current_attrnamespace);
933 current_attrnamespace = NULL;
936 * We are done with this xattr list.
939 xattr_list = (char *)NULL;
943 * If we found any xattr send them to the SD.
945 if (xattr_count > 0) {
947 * Serialize the datastream.
949 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
950 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
952 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
957 xattr_drop_internal_table(xattr_value_list);
960 * Send the datastream to the SD.
962 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
964 retval = bxattr_exit_ok;
968 if (current_attrnamespace != NULL) {
969 actuallyfree(current_attrnamespace);
971 if (xattr_list != NULL) {
974 if (xattr_value_list != NULL) {
975 xattr_drop_internal_table(xattr_value_list);
980 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
982 xattr_t *current_xattr;
983 alist *xattr_value_list;
984 int current_attrnamespace, cnt;
985 char *attrnamespace, *attrname;
988 xattr_value_list = New(alist(10, not_owned_by_alist));
990 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
991 xattr_drop_internal_table(xattr_value_list);
992 return bxattr_exit_error;
995 foreach_alist(current_xattr, xattr_value_list) {
997 * Try splitting the xattr_name into a namespace and name part.
998 * The splitting character is a .
1000 attrnamespace = current_xattr->name;
1001 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1002 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1003 current_xattr->name, jcr->last_fname);
1004 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1005 current_xattr->name, jcr->last_fname);
1011 * Make sure the attrnamespace makes sense.
1013 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1014 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1015 attrnamespace, jcr->last_fname);
1016 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1017 attrnamespace, jcr->last_fname);
1022 * Try restoring the extended attribute.
1024 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1025 attrname, current_xattr->value, current_xattr->value_length);
1026 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1032 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1033 jcr->last_fname, be.bstrerror());
1034 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1035 jcr->last_fname, be.bstrerror());
1042 xattr_drop_internal_table(xattr_value_list);
1043 return bxattr_exit_ok;
1046 xattr_drop_internal_table(xattr_value_list);
1047 return bxattr_exit_error;
1051 * Function pointers to the build and parse function to use for these xattrs.
1053 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1054 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1056 #elif defined(HAVE_SUN_OS)
1058 * Solaris extended attributes were introduced in Solaris 9
1061 * Solaris extensible attributes were introduced in OpenSolaris
1062 * by PSARC 2007/315 Solaris extensible attributes are also
1063 * sometimes called extended system attributes.
1065 * man fsattr(5) on Solaris gives a wealth of info. The most
1066 * important bits are:
1068 * Attributes are logically supported as files within the file
1069 * system. The file system is therefore augmented with an
1070 * orthogonal name space of file attributes. Any file (includ-
1071 * ing attribute files) can have an arbitrarily deep attribute
1072 * tree associated with it. Attribute values are accessed by
1073 * file descriptors obtained through a special attribute inter-
1074 * face. This logical view of "attributes as files" allows the
1075 * leveraging of existing file system interface functionality
1076 * to support the construction, deletion, and manipulation of
1079 * The special files "." and ".." retain their accustomed
1080 * semantics within the attribute hierarchy. The "." attribute
1081 * file refers to the current directory and the ".." attribute
1082 * file refers to the parent directory. The unnamed directory
1083 * at the head of each attribute tree is considered the "child"
1084 * of the file it is associated with and the ".." file refers
1085 * to the associated file. For any non-directory file with
1086 * attributes, the ".." entry in the unnamed directory refers
1087 * to a file that is not a directory.
1089 * Conceptually, the attribute model is fully general. Extended
1090 * attributes can be any type of file (doors, links, direc-
1091 * tories, and so forth) and can even have their own attributes
1092 * (fully recursive). As a result, the attributes associated
1093 * with a file could be an arbitrarily deep directory hierarchy
1094 * where each attribute could have an equally complex attribute
1095 * tree associated with it. Not all implementations are able
1096 * to, or want to, support the full model. Implementation are
1097 * therefore permitted to reject operations that are not sup-
1098 * ported. For example, the implementation for the UFS file
1099 * system allows only regular files as attributes (for example,
1100 * no sub-directories) and rejects attempts to place attributes
1103 * The following list details the operations that are rejected
1104 * in the current implementation:
1106 * link Any attempt to create links between
1107 * attribute and non-attribute space
1108 * is rejected to prevent security-
1109 * related or otherwise sensitive
1110 * attributes from being exposed, and
1111 * therefore manipulable, as regular
1114 * rename Any attempt to rename between
1115 * attribute and non-attribute space
1116 * is rejected to prevent an already
1117 * linked file from being renamed and
1118 * thereby circumventing the link res-
1121 * mkdir, symlink, mknod Any attempt to create a "non-
1122 * regular" file in attribute space is
1123 * rejected to reduce the functional-
1124 * ity, and therefore exposure and
1125 * risk, of the initial implementa-
1128 * The entire available name space has been allocated to "gen-
1129 * eral use" to bring the implementation in line with the NFSv4
1130 * draft standard [NFSv4]. That standard defines "named attri-
1131 * butes" (equivalent to Solaris Extended Attributes) with no
1132 * naming restrictions. All Sun applications making use of
1133 * opaque extended attributes will use the prefix "SUNW".
1136 #ifdef HAVE_SYS_ATTR_H
1137 #include <sys/attr.h>
1144 #ifdef HAVE_SYS_NVPAIR_H
1145 #include <sys/nvpair.h>
1148 #ifdef HAVE_SYS_ACL_H
1149 #include <sys/acl.h>
1152 #if !defined(HAVE_OPENAT) || \
1153 !defined(HAVE_UNLINKAT) || \
1154 !defined(HAVE_FCHOWNAT) || \
1155 !defined(HAVE_FUTIMESAT)
1156 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
1160 * Define the supported XATTR streams for this OS
1162 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1163 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
1165 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
1166 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
1169 * This code creates a temporary cache with entries for each xattr which has
1170 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
1172 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
1174 xattr_link_cache_entry_t *ptr;
1176 foreach_alist(ptr, jcr->xattr_data->link_cache) {
1177 if (ptr && ptr->inum == inum) {
1184 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
1186 xattr_link_cache_entry_t *ptr;
1188 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
1189 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
1191 bstrncpy(ptr->target, target, sizeof(ptr->target));
1192 jcr->xattr_data->link_cache->append(ptr);
1195 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1197 * This function returns true if a non default extended system attribute
1198 * list is associated with fd and returns false when an error has occured
1199 * or when only extended system attributes other than archive,
1200 * av_modified or crtime are set.
1202 * The function returns true for the following cases:
1204 * - any extended system attribute other than the default attributes
1205 * ('archive', 'av_modified' and 'crtime') is set
1206 * - nvlist has NULL name string
1207 * - nvpair has data type of 'nvlist'
1208 * - default data type.
1210 static bool solaris_has_non_transient_extensible_attributes(int fd)
1218 bool retval = false;
1220 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
1225 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
1226 name = nvpair_name(pair);
1229 fattr = name_to_attr(name);
1235 type = nvpair_type(pair);
1237 case DATA_TYPE_BOOLEAN_VALUE:
1238 if (nvpair_value_boolean_value(pair, &value) != 0) {
1241 if (value && fattr != F_ARCHIVE &&
1242 fattr != F_AV_MODIFIED) {
1247 case DATA_TYPE_UINT64_ARRAY:
1248 if (fattr != F_CRTIME) {
1253 case DATA_TYPE_NVLIST:
1261 if (response != NULL) {
1262 nvlist_free(response);
1266 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1268 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
1270 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1271 * There is no need to store those acls as we already store the stat bits too.
1273 static bool acl_is_trivial(int count, aclent_t *entries)
1278 for (n = 0; n < count; n++) {
1280 if (!(ace->a_type == USER_OBJ ||
1281 ace->a_type == GROUP_OBJ ||
1282 ace->a_type == OTHER_OBJ ||
1283 ace->a_type == CLASS_OBJ))
1288 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
1290 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
1293 #ifdef HAVE_EXTENDED_ACL
1299 * See if this attribute has an ACL
1301 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
1302 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
1304 * See if there is a non trivial acl on the file.
1306 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
1307 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
1310 return bxattr_exit_ok;
1312 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1313 attrname, jcr->last_fname, be.bstrerror());
1314 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
1315 attrname, jcr->last_fname, be.bstrerror());
1316 return bxattr_exit_error;
1321 #if defined(ACL_SID_FMT)
1323 * New format flag added in newer Solaris versions.
1325 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1327 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1328 #endif /* ACL_SID_FMT */
1330 *acl_text = acl_totext(aclp, flags);
1338 return bxattr_exit_ok;
1339 #else /* HAVE_EXTENDED_ACL */
1341 aclent_t *acls = NULL;
1345 * See if this attribute has an ACL
1348 n = facl(fd, GETACLCNT, 0, NULL);
1350 n = acl(attrname, GETACLCNT, 0, NULL);
1353 if (n >= MIN_ACL_ENTRIES) {
1354 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1355 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
1356 acl(attrname, GETACL, n, acls) != n) {
1360 return bxattr_exit_ok;
1362 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1363 attrname, jcr->last_fname, be.bstrerror());
1364 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
1365 attrname, jcr->last_fname, be.bstrerror());
1367 return bxattr_exit_error;
1372 * See if there is a non trivial acl on the file.
1374 if (!acl_is_trivial(n, acls)) {
1375 if ((*acl_text = acltotext(acls, n)) == NULL) {
1376 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
1377 attrname, jcr->last_fname, be.bstrerror());
1378 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
1379 attrname, jcr->last_fname, be.bstrerror());
1381 return bxattr_exit_error;
1391 return bxattr_exit_ok;
1392 #endif /* HAVE_EXTENDED_ACL */
1394 #else /* HAVE_ACL */
1395 return bxattr_exit_ok;
1396 #endif /* HAVE_ACL */
1400 * Forward declaration for recursive function call.
1402 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
1405 * Save an extended or extensible attribute.
1406 * This is stored as an opaque stream of bytes with the following encoding:
1408 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
1410 * or for a hardlinked or symlinked attribute
1412 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
1414 * xattr_name can be a subpath relative to the file the xattr is on.
1415 * stat_buffer is the string representation of the stat struct.
1416 * acl_string is an acl text when a non trivial acl is set on the xattr.
1417 * actual_xattr_data is the content of the xattr file.
1419 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
1420 const char *attrname, bool toplevel_hidden_dir, int stream)
1425 xattr_link_cache_entry_t *xlce;
1426 char target_attrname[PATH_MAX];
1427 char link_source[PATH_MAX];
1428 char *acl_text = NULL;
1429 char attribs[MAXSTRING];
1430 char buffer[XATTR_BUFSIZ];
1431 bxattr_exit_code retval = bxattr_exit_error;
1434 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
1437 * Get the stats of the extended or extensible attribute.
1439 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
1442 retval = bxattr_exit_ok;
1445 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
1446 target_attrname, jcr->last_fname, be.bstrerror());
1447 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
1448 target_attrname, jcr->last_fname, be.bstrerror());
1454 * Based on the filetype perform the correct action. We support most filetypes here, more
1455 * then the actual implementation on Solaris supports so some code may never get executed
1456 * due to limitations in the implementation.
1458 switch (st.st_mode & S_IFMT) {
1463 * Get any acl on the xattr.
1465 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1469 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1470 * Encode the stat struct into an ASCII representation.
1472 encode_stat(attribs, &st, 0, stream);
1473 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
1474 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1478 * Get any acl on the xattr.
1480 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1484 * See if this is the toplevel_hidden_dir being saved.
1486 if (toplevel_hidden_dir) {
1488 * Save the data for later storage when we encounter a real xattr. We store the data
1489 * in the jcr->xattr_data->content buffer and flush that just before sending out the
1490 * first real xattr. Encode the stat struct into an ASCII representation and jump
1491 * out of the function.
1493 encode_stat(attribs, &st, 0, stream);
1494 cnt = bsnprintf(buffer, sizeof(buffer),
1496 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1497 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1498 jcr->xattr_data->content_length = cnt;
1502 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1503 * Encode the stat struct into an ASCII representation.
1505 encode_stat(attribs, &st, 0, stream);
1506 cnt = bsnprintf(buffer, sizeof(buffer),
1508 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1513 * If this is a hardlinked file check the inode cache for a hit.
1515 if (st.st_nlink > 1) {
1517 * See if the cache already knows this inode number.
1519 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
1521 * Generate a xattr encoding with the reference to the target in there.
1523 encode_stat(attribs, &st, st.st_ino, stream);
1524 cnt = bsnprintf(buffer, sizeof(buffer),
1526 target_attrname, 0, attribs, 0, xlce->target, 0);
1527 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1528 jcr->xattr_data->content_length = cnt;
1529 retval = send_xattr_stream(jcr, stream);
1532 * For a hard linked file we are ready now, no need to recursively save the attributes.
1538 * Store this hard linked file in the cache.
1539 * Store the name relative to the top level xattr space.
1541 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
1545 * Get any acl on the xattr.
1547 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
1552 * Encode the stat struct into an ASCII representation.
1554 encode_stat(attribs, &st, 0, stream);
1555 cnt = bsnprintf(buffer, sizeof(buffer),
1557 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1560 * Open the extended or extensible attribute file.
1562 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1565 retval = bxattr_exit_ok;
1568 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1569 target_attrname, jcr->last_fname, be.bstrerror());
1570 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1571 target_attrname, jcr->last_fname, be.bstrerror());
1578 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1579 * Encode the stat struct into an ASCII representation.
1581 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1584 retval = bxattr_exit_ok;
1587 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1588 target_attrname, jcr->last_fname, be.bstrerror());
1589 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1590 target_attrname, jcr->last_fname, be.bstrerror());
1596 * Generate a xattr encoding with the reference to the target in there.
1598 encode_stat(attribs, &st, st.st_ino, stream);
1599 cnt = bsnprintf(buffer, sizeof(buffer),
1601 target_attrname, 0, attribs, 0, link_source, 0);
1602 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1603 jcr->xattr_data->content_length = cnt;
1604 retval = send_xattr_stream(jcr, stream);
1606 if (retval == bxattr_exit_ok) {
1607 jcr->xattr_data->nr_saved++;
1611 * For a soft linked file we are ready now, no need to recursively save the attributes.
1619 * See if this is the first real xattr being saved.
1620 * If it is save the toplevel_hidden_dir attributes first.
1621 * This is easy as its stored already in the jcr->xattr_data->content buffer.
1623 if (jcr->xattr_data->nr_saved == 0) {
1624 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1625 if (retval != bxattr_exit_ok) {
1628 jcr->xattr_data->nr_saved++;
1631 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1632 jcr->xattr_data->content_length = cnt;
1635 * Only dump the content of regular files.
1637 switch (st.st_mode & S_IFMT) {
1639 if (st.st_size > 0) {
1641 * Protect ourself against things getting out of hand.
1643 if (st.st_size >= MAX_XATTR_STREAM) {
1644 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1645 jcr->last_fname, MAX_XATTR_STREAM);
1649 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1650 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
1651 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
1652 jcr->xattr_data->content_length += cnt;
1656 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
1657 target_attrname, jcr->last_fname);
1658 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1659 target_attrname, jcr->last_fname);
1670 * We build a new xattr stream send it to the SD.
1672 retval = send_xattr_stream(jcr, stream);
1673 if (retval != bxattr_exit_ok) {
1676 jcr->xattr_data->nr_saved++;
1679 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1680 * available on this extended attribute.
1682 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1685 * The recursive call could change our working dir so change back to the wanted workdir.
1687 if (fchdir(fd) < 0) {
1690 retval = bxattr_exit_ok;
1694 _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1695 jcr->last_fname, be.bstrerror());
1696 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1697 jcr->last_fname, fd, be.bstrerror());
1703 if (acl_text != NULL) {
1712 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1715 int fd, filefd = -1, attrdirfd = -1;
1718 char current_xattr_namespace[PATH_MAX];
1719 bxattr_exit_code retval = bxattr_exit_error;
1723 * Determine what argument to use. Use attr_parent when set
1724 * (recursive call) or jcr->last_fname for first call. Also save
1725 * the current depth of the xattr_space we are in.
1729 if (xattr_namespace) {
1730 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1731 xattr_namespace, attr_parent);
1733 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1736 name = jcr->last_fname;
1737 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1741 * Open the file on which to save the xattrs read-only.
1743 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1746 retval = bxattr_exit_ok;
1749 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1750 jcr->last_fname, be.bstrerror());
1751 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1752 jcr->last_fname, be.bstrerror());
1758 * Open the xattr naming space.
1760 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1764 * Gentile way of the system saying this type of xattr layering is not supported.
1765 * Which is not problem we just forget about this this xattr.
1766 * But as this is not an error we return a positive return value.
1768 retval = bxattr_exit_ok;
1771 retval = bxattr_exit_ok;
1774 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1775 name, jcr->last_fname, be.bstrerror());
1776 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1777 name, jcr->last_fname, be.bstrerror());
1783 * We need to change into the attribute directory to determine if each of the
1784 * attributes should be saved.
1786 if (fchdir(attrdirfd) < 0) {
1787 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1788 jcr->last_fname, be.bstrerror());
1789 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1790 jcr->last_fname, attrdirfd, be.bstrerror());
1795 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1796 * else because the readdir returns "." entry after the extensible attr entry.
1797 * And as we want this entry before anything else we better just save its data.
1800 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1801 true, STREAM_XATTR_SOLARIS);
1803 if ((fd = dup(attrdirfd)) == -1 ||
1804 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1805 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1806 jcr->last_fname, be.bstrerror());
1807 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1808 jcr->last_fname, fd, be.bstrerror());
1814 * Walk the namespace.
1816 while (dp = readdir(dirp)) {
1818 * Skip only the toplevel . dir.
1820 if (!attr_parent && bstrcmp(dp->d_name, "."))
1824 * Skip all .. directories
1826 if (bstrcmp(dp->d_name, ".."))
1829 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1830 current_xattr_namespace, dp->d_name, jcr->last_fname);
1832 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1834 * We are not interested in read-only extensible attributes.
1836 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
1837 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1838 current_xattr_namespace, dp->d_name, jcr->last_fname);
1844 * We are only interested in read-write extensible attributes
1845 * when they contain non-transient values.
1847 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
1849 * Determine if there are non-transient system attributes at the toplevel.
1850 * We need to provide a fd to the open file.
1852 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1853 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1854 current_xattr_namespace, dp->d_name, jcr->last_fname);
1861 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1862 false, STREAM_XATTR_SOLARIS_SYS);
1865 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1870 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1871 false, STREAM_XATTR_SOLARIS);
1875 retval = bxattr_exit_ok;
1878 if (attrdirfd != -1)
1886 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1888 #ifdef HAVE_EXTENDED_ACL
1893 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1894 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
1896 return bxattr_exit_error;
1899 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1900 acl_set(attrname, aclp) != 0) {
1901 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1902 attrname, jcr->last_fname, be.bstrerror());
1903 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1904 attrname, jcr->last_fname, be.bstrerror());
1905 return bxattr_exit_error;
1911 return bxattr_exit_ok;
1913 #else /* HAVE_EXTENDED_ACL */
1915 aclent_t *acls = NULL;
1918 acls = aclfromtext(acl_text, &n);
1920 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1921 acl(attrname, SETACL, n, acls) != 0) {
1922 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1923 attrname, jcr->last_fname, be.bstrerror());
1924 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1925 attrname, jcr->last_fname, be.bstrerror());
1926 return bxattr_exit_error;
1933 return bxattr_exit_ok;
1935 #endif /* HAVE_EXTENDED_ACL */
1938 #endif /* HAVE_ACL */
1940 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1942 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1943 int used_bytes, total_bytes, cnt;
1944 char *bp, *target_attrname, *attribs;
1945 char *linked_target = NULL;
1946 char *acl_text = NULL;
1950 struct timeval times[2];
1951 bxattr_exit_code retval = bxattr_exit_error;
1955 * Parse the xattr stream. First the part that is the same for all xattrs.
1958 total_bytes = jcr->xattr_data->content_length;
1961 * The name of the target xattr has a leading / we are not interested
1962 * in that so skip it when decoding the string. We always start a the /
1963 * of the xattr space anyway.
1965 target_attrname = jcr->xattr_data->content + 1;
1966 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1967 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1973 * Open the file on which to restore the xattrs read-only.
1975 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1976 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1977 jcr->last_fname, be.bstrerror());
1978 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1979 jcr->last_fname, be.bstrerror());
1984 * Open the xattr naming space and make it the current working dir.
1986 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1987 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1988 jcr->last_fname, be.bstrerror());
1989 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1990 jcr->last_fname, be.bstrerror());
1994 if (fchdir(attrdirfd) < 0) {
1995 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1996 jcr->last_fname, be.bstrerror());
1997 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1998 jcr->last_fname, attrdirfd, be.bstrerror());
2003 * Try to open the correct xattr subdir based on the target_attrname given.
2004 * e.g. check if its a subdir attrname. Each / in the string makes us go
2007 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2010 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2011 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2012 target_attrname, jcr->last_fname, be.bstrerror());
2013 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2014 target_attrname, jcr->last_fname, be.bstrerror());
2022 * Open the xattr naming space.
2024 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2025 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2026 target_attrname, jcr->last_fname, be.bstrerror());
2027 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2028 target_attrname, jcr->last_fname, be.bstrerror());
2036 * Make the xattr space our current workingdir.
2038 if (fchdir(attrdirfd) < 0) {
2039 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2040 target_attrname, jcr->last_fname, be.bstrerror());
2041 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2042 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2046 target_attrname = ++bp;
2050 * Decode the attributes from the stream.
2052 decode_stat(attribs, &st, &inum);
2055 * Decode the next field (acl_text).
2057 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2058 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2064 * Based on the filetype perform the correct action. We support most filetypes here, more
2065 * then the actual implementation on Solaris supports so some code may never get executed
2066 * due to limitations in the implementation.
2068 switch (st.st_mode & S_IFMT) {
2071 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2073 unlinkat(attrdirfd, target_attrname, 0);
2074 if (mkfifo(target_attrname, st.st_mode) < 0) {
2075 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
2076 target_attrname, jcr->last_fname, be.bstrerror());
2077 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
2078 target_attrname, jcr->last_fname, be.bstrerror());
2085 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2087 unlinkat(attrdirfd, target_attrname, 0);
2088 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
2089 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
2090 target_attrname, jcr->last_fname, be.bstrerror());
2091 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
2092 target_attrname, jcr->last_fname, be.bstrerror());
2098 * If its not the hidden_dir create the entry.
2099 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2101 if (!bstrcmp(target_attrname, ".")) {
2102 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
2103 if (mkdir(target_attrname, st.st_mode) < 0) {
2104 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
2105 target_attrname, jcr->last_fname, be.bstrerror());
2106 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
2107 target_attrname, jcr->last_fname, be.bstrerror());
2114 * See if this is a hard linked file. e.g. inum != 0
2119 unlinkat(attrdirfd, target_attrname, 0);
2120 if (link(linked_target, target_attrname) < 0) {
2121 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
2122 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2123 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
2124 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2129 * Successfully restored xattr.
2131 retval = bxattr_exit_ok;
2134 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
2135 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
2139 if (used_bytes < (total_bytes - 1))
2143 * Restore the actual xattr.
2145 if (!is_extensible) {
2146 unlinkat(attrdirfd, target_attrname, 0);
2149 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
2150 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2151 target_attrname, jcr->last_fname, be.bstrerror());
2152 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2153 target_attrname, jcr->last_fname, be.bstrerror());
2159 * Restore the actual data.
2161 if (st.st_size > 0) {
2162 used_bytes = (data - jcr->xattr_data->content);
2163 cnt = total_bytes - used_bytes;
2166 * Do a sanity check, the st.st_size should be the same as the number of bytes
2167 * we have available as data of the stream.
2169 if (cnt != st.st_size) {
2170 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
2171 target_attrname, jcr->last_fname);
2172 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
2173 target_attrname, jcr->last_fname);
2178 cnt = write(attrfd, data, cnt);
2180 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
2181 target_attrname, jcr->last_fname, be.bstrerror());
2182 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
2183 target_attrname, jcr->last_fname, be.bstrerror());
2189 cnt = total_bytes - used_bytes;
2195 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2199 if (symlink(linked_target, target_attrname) < 0) {
2200 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
2201 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2202 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
2203 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2208 * Successfully restored xattr.
2210 retval = bxattr_exit_ok;
2217 * Restore owner and acl for non extensible attributes.
2219 if (!is_extensible) {
2220 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
2224 * Gentile way of the system saying this type of xattr layering is not supported.
2225 * But as this is not an error we return a positive return value.
2227 retval = bxattr_exit_ok;
2230 retval = bxattr_exit_ok;
2233 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
2234 target_attrname, jcr->last_fname, be.bstrerror());
2235 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
2236 target_attrname, jcr->last_fname, be.bstrerror());
2243 if (acl_text && *acl_text)
2244 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
2246 #endif /* HAVE_ACL */
2249 * For a non extensible attribute restore access and modification time on the xattr.
2251 if (!is_extensible) {
2252 times[0].tv_sec = st.st_atime;
2253 times[0].tv_usec = 0;
2254 times[1].tv_sec = st.st_mtime;
2255 times[1].tv_usec = 0;
2257 if (futimesat(attrdirfd, target_attrname, times) < 0) {
2258 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
2259 target_attrname, jcr->last_fname, be.bstrerror());
2260 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
2261 target_attrname, jcr->last_fname, be.bstrerror());
2267 * Successfully restored xattr.
2269 retval = bxattr_exit_ok;
2273 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
2275 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
2282 if (attrdirfd != -1) {
2291 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2294 bxattr_exit_code retval = bxattr_exit_ok;
2297 * First see if extended attributes or extensible attributes are present.
2298 * If not just pretend things went ok.
2300 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
2301 jcr->xattr_data->nr_saved = 0;
2302 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
2305 * As we change the cwd in the save function save the current cwd
2306 * for restore after return from the solaris_save_xattrs function.
2308 getcwd(cwd, sizeof(cwd));
2309 retval = solaris_save_xattrs(jcr, NULL, NULL);
2311 delete jcr->xattr_data->link_cache;
2312 jcr->xattr_data->link_cache = NULL;
2317 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
2320 bool is_extensible = false;
2321 bxattr_exit_code retval;
2324 * First make sure we can restore xattr on the filesystem.
2327 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2328 case STREAM_XATTR_SOLARIS_SYS:
2329 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
2330 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
2331 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
2333 return bxattr_exit_error;
2336 is_extensible = true;
2339 case STREAM_XATTR_SOLARIS:
2340 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
2341 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
2342 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
2344 return bxattr_exit_error;
2348 return bxattr_exit_error;
2352 * As we change the cwd in the restore function save the current cwd
2353 * for restore after return from the solaris_restore_xattrs function.
2355 getcwd(cwd, sizeof(cwd));
2356 retval = solaris_restore_xattrs(jcr, is_extensible);
2363 * Function pointers to the build and parse function to use for these xattrs.
2365 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
2366 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
2368 #endif /* defined(HAVE_SUN_OS) */
2371 * Entry points when compiled with support for XATTRs on a supported platform.
2373 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2375 if (os_build_xattr_streams) {
2376 return (*os_build_xattr_streams)(jcr, ff_pkt);
2378 return bxattr_exit_error;
2381 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
2385 if (os_parse_xattr_streams) {
2387 * See if we can parse this stream, and ifso give it a try.
2389 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
2390 if (os_default_xattr_streams[cnt] == stream) {
2391 return (*os_parse_xattr_streams)(jcr, stream);
2396 * Issue a warning and discard the message. But pretend the restore was ok.
2398 Jmsg2(jcr, M_WARNING, 0,
2399 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
2400 jcr->last_fname, stream);
2401 return bxattr_exit_error;