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;
211 bxattr_exit_code retval = bxattr_exit_ok;
214 * Parse the stream and call restore_xattr_on_file for each extended attribute.
216 * Start unserializing the data. We keep on looping while we have not
217 * unserialized all bytes in the stream.
219 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
220 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
222 * First make sure the magic is present. This way we can easily catch corruption.
223 * Any missing MAGIC is fatal we do NOT try to continue.
226 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
227 unser_uint32(current_xattr->magic);
228 if (current_xattr->magic != XATTR_MAGIC) {
229 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
231 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
234 return bxattr_exit_error;
238 * Decode the valuepair. First decode the length of the name.
240 unser_uint32(current_xattr->name_length);
241 if (current_xattr->name_length == 0) {
242 Mmsg1(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
244 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
247 return bxattr_exit_error;
251 * Allocate room for the name and decode its content.
253 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
254 unser_bytes(current_xattr->name, current_xattr->name_length);
257 * The xattr_name needs to be null terminated for lsetxattr.
259 current_xattr->name[current_xattr->name_length] = '\0';
262 * Decode the value length.
264 unser_uint32(current_xattr->value_length);
266 if (current_xattr->value_length > 0) {
268 * Allocate room for the value and decode its content.
270 current_xattr->value = (char *)malloc(current_xattr->value_length);
271 unser_bytes(current_xattr->value, current_xattr->value_length);
273 current_xattr->value = NULL;
276 xattr_value_list->append(current_xattr);
279 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
285 * This is a supported OS, See what kind of interface we should use.
287 #if defined(HAVE_DARWIN_OS) || \
288 defined(HAVE_LINUX_OS)
290 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
291 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
292 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
293 #error "Missing either full support for the LXATTR or XATTR functions."
296 #ifdef HAVE_SYS_XATTR_H
297 #include <sys/xattr.h>
299 #error "Missing sys/xattr.h header file"
303 * Define the supported XATTR streams for this OS
305 #if defined(HAVE_DARWIN_OS)
306 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
307 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
308 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
309 #elif defined(HAVE_LINUX_OS)
310 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
311 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
312 static const char *xattr_skiplist[1] = { NULL };
316 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
317 * listxattr, getxattr and setxattr with an extra options argument
318 * which mimics the l variants of the functions when we specify
319 * XATTR_NOFOLLOW as the options value.
321 #if defined(HAVE_DARWIN_OS)
322 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
323 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
324 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
327 * Fallback to the non l-functions when those are not available.
329 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
330 #define lgetxattr getxattr
332 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
333 #define lsetxattr setxattr
335 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
336 #define llistxattr listxattr
340 static bxattr_exit_code linux_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
343 char *xattr_list, *bp;
344 int cnt, xattr_count = 0;
345 int32_t xattr_list_len,
347 uint32_t expected_serialize_len = 0;
348 xattr_t *current_xattr;
349 alist *xattr_value_list = NULL;
350 bxattr_exit_code retval = bxattr_exit_error;
354 * First get the length of the available list with extended attributes.
356 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
357 switch (xattr_list_len) {
361 return bxattr_exit_ok;
363 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
364 jcr->last_fname, be.bstrerror());
365 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
366 jcr->last_fname, be.bstrerror());
367 return bxattr_exit_error;
371 return bxattr_exit_ok;
377 * Allocate room for the extented attribute list.
379 xattr_list = (char *)malloc(xattr_list_len + 1);
380 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
383 * Get the actual list of extended attributes names for a file.
385 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
386 switch (xattr_list_len) {
390 retval = bxattr_exit_ok;
393 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
394 jcr->last_fname, be.bstrerror());
395 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
396 jcr->last_fname, be.bstrerror());
403 xattr_list[xattr_list_len] = '\0';
405 xattr_value_list = New(alist(10, not_owned_by_alist));
408 * Walk the list of extended attributes names and retrieve the data.
409 * We already count the bytes needed for serializing the stream later on.
412 while ((bp - xattr_list) + 1 < xattr_list_len) {
417 * On some OSes you also get the acls in the extented attribute list.
418 * So we check if we are already backing up acls and if we do we
419 * don't store the extended attribute with the same info.
421 if (ff_pkt->flags & FO_ACL) {
422 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
423 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
431 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
434 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
435 if (bstrcmp(bp, xattr_skiplist[cnt])) {
442 name_len = strlen(bp);
443 if (skip_xattr || name_len == 0) {
444 bp = strchr(bp, '\0') + 1;
449 * Each xattr valuepair starts with a magic so we can parse it easier.
451 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
452 current_xattr->magic = XATTR_MAGIC;
453 expected_serialize_len += sizeof(current_xattr->magic);
456 * Allocate space for storing the name.
458 current_xattr->name_length = name_len;
459 current_xattr->name = (char *)malloc(current_xattr->name_length);
460 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
462 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
465 * First see how long the value is for the extended attribute.
467 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
468 switch (xattr_value_len) {
472 retval = bxattr_exit_ok;
473 free(current_xattr->name);
477 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
478 jcr->last_fname, be.bstrerror());
479 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
480 jcr->last_fname, be.bstrerror());
481 free(current_xattr->name);
487 current_xattr->value = NULL;
488 current_xattr->value_length = 0;
489 expected_serialize_len += sizeof(current_xattr->value_length);
493 * Allocate space for storing the value.
495 current_xattr->value = (char *)malloc(xattr_value_len);
496 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
498 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
499 if (xattr_value_len < 0) {
502 retval = bxattr_exit_ok;
503 free(current_xattr->value);
504 free(current_xattr->name);
508 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
509 jcr->last_fname, be.bstrerror());
510 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
511 jcr->last_fname, be.bstrerror());
512 free(current_xattr->value);
513 free(current_xattr->name);
519 * Store the actual length of the value.
521 current_xattr->value_length = xattr_value_len;
522 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
525 * Protect ourself against things getting out of hand.
527 if (expected_serialize_len >= MAX_XATTR_STREAM) {
528 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
529 jcr->last_fname, MAX_XATTR_STREAM);
530 free(current_xattr->value);
531 free(current_xattr->name);
537 xattr_value_list->append(current_xattr);
539 bp = strchr(bp, '\0') + 1;
544 xattr_list = (char *)NULL;
547 * If we found any xattr send them to the SD.
549 if (xattr_count > 0) {
551 * Serialize the datastream.
553 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
554 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
556 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
561 xattr_drop_internal_table(xattr_value_list);
564 * Send the datastream to the SD.
566 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
568 xattr_drop_internal_table(xattr_value_list);
570 return bxattr_exit_ok;
574 if (xattr_list != NULL) {
577 if (xattr_value_list != NULL) {
578 xattr_drop_internal_table(xattr_value_list);
583 static bxattr_exit_code linux_xattr_parse_streams(JCR *jcr, int stream)
585 xattr_t *current_xattr;
586 alist *xattr_value_list;
589 xattr_value_list = New(alist(10, not_owned_by_alist));
591 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
592 xattr_drop_internal_table(xattr_value_list);
593 return bxattr_exit_error;
596 foreach_alist(current_xattr, xattr_value_list) {
597 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
602 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
603 jcr->last_fname, be.bstrerror());
604 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
605 jcr->last_fname, be.bstrerror());
611 xattr_drop_internal_table(xattr_value_list);
612 return bxattr_exit_ok;
615 xattr_drop_internal_table(xattr_value_list);
616 return bxattr_exit_error;
620 * Function pointers to the build and parse function to use for these xattrs.
622 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = linux_xattr_build_streams;
623 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = linux_xattr_parse_streams;
625 #elif defined(HAVE_FREEBSD_OS) || \
626 defined(HAVE_NETBSD_OS) || \
627 defined(HAVE_OPENBSD_OS)
629 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
630 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
631 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
632 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
633 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
634 #error "Missing full support for the extattr functions."
637 #ifdef HAVE_SYS_EXTATTR_H
638 #include <sys/extattr.h>
640 #error "Missing sys/extattr.h header file"
643 #ifdef HAVE_LIBUTIL_H
647 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
648 #define extattr_get_link extattr_get_file
650 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
651 #define extattr_set_link extattr_set_file
653 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
654 #define extattr_list_link extattr_list_file
657 #if defined(HAVE_FREEBSD_OS)
658 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
659 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
660 static const char *xattr_acl_skiplist[2] = { "system.posix1e.acl_access", NULL };
661 static const char *xattr_skiplist[1] = { NULL };
662 #elif defined(HAVE_NETBSD_OS)
663 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
664 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
665 static const char *xattr_acl_skiplist[1] = { NULL };
666 static const char *xattr_skiplist[1] = { NULL };
667 #elif defined(HAVE_OPENBSD_OS)
668 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
669 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
670 static const char *xattr_acl_skiplist[1] = { NULL };
671 static const char *xattr_skiplist[1] = { NULL };
674 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
678 int cnt, index, xattr_count = 0;
679 int32_t xattr_list_len,
681 uint32_t expected_serialize_len = 0;
682 unsigned int namespace_index;
684 char *current_attrnamespace = NULL;
685 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
686 xattr_t *current_xattr;
687 alist *xattr_value_list = NULL;
688 bxattr_exit_code retval = bxattr_exit_error;
691 xattr_value_list = New(alist(10, not_owned_by_alist));
694 * Loop over all available xattr namespaces.
696 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
697 attrnamespace = os_default_xattr_namespaces[namespace_index];
700 * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
701 * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
703 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
704 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
705 attrnamespace, jcr->last_fname);
706 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
707 attrnamespace, jcr->last_fname);
712 * First get the length of the available list with extended attributes.
713 * If we get EPERM on system namespace, don't return error.
714 * This is expected for normal users trying to archive the system
715 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
716 * they've decided to return EOPNOTSUPP instead.
718 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
719 switch (xattr_list_len) {
723 retval = bxattr_exit_ok;
725 #if defined(EOPNOTSUPP)
729 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
730 actuallyfree(current_attrnamespace);
731 current_attrnamespace = NULL;
738 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
739 jcr->last_fname, be.bstrerror());
740 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
741 jcr->last_fname, be.bstrerror());
752 * Allocate room for the extented attribute list.
754 xattr_list = (char *)malloc(xattr_list_len + 1);
755 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
758 * Get the actual list of extended attributes names for a file.
760 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
761 switch (xattr_list_len) {
765 retval = bxattr_exit_ok;
768 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
769 jcr->last_fname, be.bstrerror());
770 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
771 jcr->last_fname, be.bstrerror());
778 xattr_list[xattr_list_len] = '\0';
781 * Walk the list of extended attributes names and retrieve the data.
782 * We already count the bytes needed for serializing the stream later on.
784 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
788 * Print the current name into the buffer as its not null terminated we need to
789 * use the length encoded in the string for copying only the needed bytes.
791 cnt = xattr_list[index];
792 if (cnt > ((int)sizeof(current_attrname) - 1)) {
793 cnt = ((int)sizeof(current_attrname) - 1);
795 strncpy(current_attrname, xattr_list + (index + 1), cnt);
796 current_attrname[cnt] = '\0';
799 * First make a xattr tuple of the current namespace and the name of the xattr.
800 * e.g. something like user.<attrname> or system.<attrname>
802 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
805 * On some OSes you also get the acls in the extented attribute list.
806 * So we check if we are already backing up acls and if we do we
807 * don't store the extended attribute with the same info.
809 if (ff_pkt->flags & FO_ACL) {
810 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
811 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
819 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
822 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
823 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
835 * Each xattr valuepair starts with a magic so we can parse it easier.
837 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
838 current_xattr->magic = XATTR_MAGIC;
839 expected_serialize_len += sizeof(current_xattr->magic);
842 * Allocate space for storing the name.
844 current_xattr->name_length = strlen(current_attrtuple);
845 current_xattr->name = (char *)malloc(current_xattr->name_length);
846 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
848 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
851 * First see how long the value is for the extended attribute.
853 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
854 switch (xattr_value_len) {
858 retval = bxattr_exit_ok;
859 free(current_xattr->name);
863 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
864 jcr->last_fname, be.bstrerror());
865 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
866 jcr->last_fname, be.bstrerror());
867 free(current_xattr->name);
873 current_xattr->value = NULL;
874 current_xattr->value_length = 0;
875 expected_serialize_len += sizeof(current_xattr->value_length);
879 * Allocate space for storing the value.
881 current_xattr->value = (char *)malloc(xattr_value_len);
882 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
884 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
885 if (xattr_value_len < 0) {
888 retval = bxattr_exit_ok;
889 free(current_xattr->value);
890 free(current_xattr->name);
894 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
895 jcr->last_fname, be.bstrerror());
896 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
897 jcr->last_fname, be.bstrerror());
898 free(current_xattr->value);
899 free(current_xattr->name);
906 * Store the actual length of the value.
908 current_xattr->value_length = xattr_value_len;
909 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
912 * Protect ourself against things getting out of hand.
914 if (expected_serialize_len >= MAX_XATTR_STREAM) {
915 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
916 jcr->last_fname, MAX_XATTR_STREAM);
917 free(current_xattr->value);
918 free(current_xattr->name);
925 xattr_value_list->append(current_xattr);
931 * Drop the local copy of the current_attrnamespace.
933 actuallyfree(current_attrnamespace);
934 current_attrnamespace = NULL;
937 * We are done with this xattr list.
940 xattr_list = (char *)NULL;
944 * If we found any xattr send them to the SD.
946 if (xattr_count > 0) {
948 * Serialize the datastream.
950 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
951 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
953 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
958 xattr_drop_internal_table(xattr_value_list);
961 * Send the datastream to the SD.
963 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
965 xattr_drop_internal_table(xattr_value_list);
967 return bxattr_exit_ok;
971 if (current_attrnamespace != NULL) {
972 actuallyfree(current_attrnamespace);
974 if (xattr_list != NULL) {
977 if (xattr_value_list != NULL) {
978 xattr_drop_internal_table(xattr_value_list);
983 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
985 xattr_t *current_xattr;
986 alist *xattr_value_list;
987 int current_attrnamespace, cnt;
988 char *attrnamespace, *attrname;
991 xattr_value_list = New(alist(10, not_owned_by_alist));
993 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
994 xattr_drop_internal_table(xattr_value_list);
995 return bxattr_exit_error;
998 foreach_alist(current_xattr, xattr_value_list) {
1000 * Try splitting the xattr_name into a namespace and name part.
1001 * The splitting character is a .
1003 attrnamespace = current_xattr->name;
1004 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1005 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1006 current_xattr->name, jcr->last_fname);
1007 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1008 current_xattr->name, jcr->last_fname);
1014 * Make sure the attrnamespace makes sense.
1016 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1017 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1018 attrnamespace, jcr->last_fname);
1019 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1020 attrnamespace, jcr->last_fname);
1025 * Try restoring the extended attribute.
1027 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1028 attrname, current_xattr->value, current_xattr->value_length);
1029 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1035 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1036 jcr->last_fname, be.bstrerror());
1037 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1038 jcr->last_fname, be.bstrerror());
1045 xattr_drop_internal_table(xattr_value_list);
1046 return bxattr_exit_ok;
1049 xattr_drop_internal_table(xattr_value_list);
1050 return bxattr_exit_error;
1054 * Function pointers to the build and parse function to use for these xattrs.
1056 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1057 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1059 #elif defined(HAVE_SUN_OS)
1061 * Solaris extended attributes were introduced in Solaris 9
1064 * Solaris extensible attributes were introduced in OpenSolaris
1065 * by PSARC 2007/315 Solaris extensible attributes are also
1066 * sometimes called extended system attributes.
1068 * man fsattr(5) on Solaris gives a wealth of info. The most
1069 * important bits are:
1071 * Attributes are logically supported as files within the file
1072 * system. The file system is therefore augmented with an
1073 * orthogonal name space of file attributes. Any file (includ-
1074 * ing attribute files) can have an arbitrarily deep attribute
1075 * tree associated with it. Attribute values are accessed by
1076 * file descriptors obtained through a special attribute inter-
1077 * face. This logical view of "attributes as files" allows the
1078 * leveraging of existing file system interface functionality
1079 * to support the construction, deletion, and manipulation of
1082 * The special files "." and ".." retain their accustomed
1083 * semantics within the attribute hierarchy. The "." attribute
1084 * file refers to the current directory and the ".." attribute
1085 * file refers to the parent directory. The unnamed directory
1086 * at the head of each attribute tree is considered the "child"
1087 * of the file it is associated with and the ".." file refers
1088 * to the associated file. For any non-directory file with
1089 * attributes, the ".." entry in the unnamed directory refers
1090 * to a file that is not a directory.
1092 * Conceptually, the attribute model is fully general. Extended
1093 * attributes can be any type of file (doors, links, direc-
1094 * tories, and so forth) and can even have their own attributes
1095 * (fully recursive). As a result, the attributes associated
1096 * with a file could be an arbitrarily deep directory hierarchy
1097 * where each attribute could have an equally complex attribute
1098 * tree associated with it. Not all implementations are able
1099 * to, or want to, support the full model. Implementation are
1100 * therefore permitted to reject operations that are not sup-
1101 * ported. For example, the implementation for the UFS file
1102 * system allows only regular files as attributes (for example,
1103 * no sub-directories) and rejects attempts to place attributes
1106 * The following list details the operations that are rejected
1107 * in the current implementation:
1109 * link Any attempt to create links between
1110 * attribute and non-attribute space
1111 * is rejected to prevent security-
1112 * related or otherwise sensitive
1113 * attributes from being exposed, and
1114 * therefore manipulable, as regular
1117 * rename Any attempt to rename between
1118 * attribute and non-attribute space
1119 * is rejected to prevent an already
1120 * linked file from being renamed and
1121 * thereby circumventing the link res-
1124 * mkdir, symlink, mknod Any attempt to create a "non-
1125 * regular" file in attribute space is
1126 * rejected to reduce the functional-
1127 * ity, and therefore exposure and
1128 * risk, of the initial implementa-
1131 * The entire available name space has been allocated to "gen-
1132 * eral use" to bring the implementation in line with the NFSv4
1133 * draft standard [NFSv4]. That standard defines "named attri-
1134 * butes" (equivalent to Solaris Extended Attributes) with no
1135 * naming restrictions. All Sun applications making use of
1136 * opaque extended attributes will use the prefix "SUNW".
1139 #ifdef HAVE_SYS_ATTR_H
1140 #include <sys/attr.h>
1147 #ifdef HAVE_SYS_NVPAIR_H
1148 #include <sys/nvpair.h>
1151 #ifdef HAVE_SYS_ACL_H
1152 #include <sys/acl.h>
1155 #if !defined(HAVE_OPENAT) || \
1156 !defined(HAVE_UNLINKAT) || \
1157 !defined(HAVE_FCHOWNAT) || \
1158 !defined(HAVE_FUTIMESAT)
1159 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
1163 * Define the supported XATTR streams for this OS
1165 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1166 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
1168 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
1169 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
1172 * This code creates a temporary cache with entries for each xattr which has
1173 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
1175 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
1177 xattr_link_cache_entry_t *ptr;
1179 foreach_alist(ptr, jcr->xattr_data->link_cache) {
1180 if (ptr && ptr->inum == inum) {
1187 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
1189 xattr_link_cache_entry_t *ptr;
1191 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
1192 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
1194 bstrncpy(ptr->target, target, sizeof(ptr->target));
1195 jcr->xattr_data->link_cache->append(ptr);
1198 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1200 * This function returns true if a non default extended system attribute
1201 * list is associated with fd and returns false when an error has occured
1202 * or when only extended system attributes other than archive,
1203 * av_modified or crtime are set.
1205 * The function returns true for the following cases:
1207 * - any extended system attribute other than the default attributes
1208 * ('archive', 'av_modified' and 'crtime') is set
1209 * - nvlist has NULL name string
1210 * - nvpair has data type of 'nvlist'
1211 * - default data type.
1213 static bool solaris_has_non_transient_extensible_attributes(int fd)
1221 bool retval = false;
1223 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
1228 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
1229 name = nvpair_name(pair);
1232 fattr = name_to_attr(name);
1238 type = nvpair_type(pair);
1240 case DATA_TYPE_BOOLEAN_VALUE:
1241 if (nvpair_value_boolean_value(pair, &value) != 0) {
1244 if (value && fattr != F_ARCHIVE &&
1245 fattr != F_AV_MODIFIED) {
1250 case DATA_TYPE_UINT64_ARRAY:
1251 if (fattr != F_CRTIME) {
1256 case DATA_TYPE_NVLIST:
1264 if (response != NULL) {
1265 nvlist_free(response);
1269 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1271 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
1273 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1274 * There is no need to store those acls as we already store the stat bits too.
1276 static bool acl_is_trivial(int count, aclent_t *entries)
1281 for (n = 0; n < count; n++) {
1283 if (!(ace->a_type == USER_OBJ ||
1284 ace->a_type == GROUP_OBJ ||
1285 ace->a_type == OTHER_OBJ ||
1286 ace->a_type == CLASS_OBJ))
1291 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
1293 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
1296 #ifdef HAVE_EXTENDED_ACL
1302 * See if this attribute has an ACL
1304 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
1305 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
1307 * See if there is a non trivial acl on the file.
1309 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
1310 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
1313 return bxattr_exit_ok;
1315 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1316 attrname, jcr->last_fname, be.bstrerror());
1317 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
1318 attrname, jcr->last_fname, be.bstrerror());
1319 return bxattr_exit_error;
1324 #if defined(ACL_SID_FMT)
1326 * New format flag added in newer Solaris versions.
1328 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1330 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1331 #endif /* ACL_SID_FMT */
1333 *acl_text = acl_totext(aclp, flags);
1341 return bxattr_exit_ok;
1342 #else /* HAVE_EXTENDED_ACL */
1344 aclent_t *acls = NULL;
1348 * See if this attribute has an ACL
1351 n = facl(fd, GETACLCNT, 0, NULL);
1353 n = acl(attrname, GETACLCNT, 0, NULL);
1356 if (n >= MIN_ACL_ENTRIES) {
1357 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1358 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
1359 acl(attrname, GETACL, n, acls) != n) {
1363 return bxattr_exit_ok;
1365 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1366 attrname, jcr->last_fname, be.bstrerror());
1367 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
1368 attrname, jcr->last_fname, be.bstrerror());
1370 return bxattr_exit_error;
1375 * See if there is a non trivial acl on the file.
1377 if (!acl_is_trivial(n, acls)) {
1378 if ((*acl_text = acltotext(acls, n)) == NULL) {
1379 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
1380 attrname, jcr->last_fname, be.bstrerror());
1381 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
1382 attrname, jcr->last_fname, be.bstrerror());
1384 return bxattr_exit_error;
1394 return bxattr_exit_ok;
1395 #endif /* HAVE_EXTENDED_ACL */
1397 #else /* HAVE_ACL */
1398 return bxattr_exit_ok;
1399 #endif /* HAVE_ACL */
1403 * Forward declaration for recursive function call.
1405 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
1408 * Save an extended or extensible attribute.
1409 * This is stored as an opaque stream of bytes with the following encoding:
1411 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
1413 * or for a hardlinked or symlinked attribute
1415 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
1417 * xattr_name can be a subpath relative to the file the xattr is on.
1418 * stat_buffer is the string representation of the stat struct.
1419 * acl_string is an acl text when a non trivial acl is set on the xattr.
1420 * actual_xattr_data is the content of the xattr file.
1422 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
1423 const char *attrname, bool toplevel_hidden_dir, int stream)
1428 xattr_link_cache_entry_t *xlce;
1429 char target_attrname[PATH_MAX];
1430 char link_source[PATH_MAX];
1431 char *acl_text = NULL;
1432 char attribs[MAXSTRING];
1433 char buffer[XATTR_BUFSIZ];
1434 bxattr_exit_code retval = bxattr_exit_error;
1437 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
1440 * Get the stats of the extended or extensible attribute.
1442 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
1445 retval = bxattr_exit_ok;
1448 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
1449 target_attrname, jcr->last_fname, be.bstrerror());
1450 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
1451 target_attrname, jcr->last_fname, be.bstrerror());
1457 * Based on the filetype perform the correct action. We support most filetypes here, more
1458 * then the actual implementation on Solaris supports so some code may never get executed
1459 * due to limitations in the implementation.
1461 switch (st.st_mode & S_IFMT) {
1466 * Get any acl on the xattr.
1468 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1472 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1473 * Encode the stat struct into an ASCII representation.
1475 encode_stat(attribs, &st, 0, stream);
1476 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
1477 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1481 * Get any acl on the xattr.
1483 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1487 * See if this is the toplevel_hidden_dir being saved.
1489 if (toplevel_hidden_dir) {
1491 * Save the data for later storage when we encounter a real xattr. We store the data
1492 * in the jcr->xattr_data->content buffer and flush that just before sending out the
1493 * first real xattr. Encode the stat struct into an ASCII representation and jump
1494 * out of the function.
1496 encode_stat(attribs, &st, 0, stream);
1497 cnt = bsnprintf(buffer, sizeof(buffer),
1499 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1500 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1501 jcr->xattr_data->content_length = cnt;
1505 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1506 * Encode the stat struct into an ASCII representation.
1508 encode_stat(attribs, &st, 0, stream);
1509 cnt = bsnprintf(buffer, sizeof(buffer),
1511 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1516 * If this is a hardlinked file check the inode cache for a hit.
1518 if (st.st_nlink > 1) {
1520 * See if the cache already knows this inode number.
1522 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
1524 * Generate a xattr encoding with the reference to the target in there.
1526 encode_stat(attribs, &st, st.st_ino, stream);
1527 cnt = bsnprintf(buffer, sizeof(buffer),
1529 target_attrname, 0, attribs, 0, xlce->target, 0);
1530 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1531 jcr->xattr_data->content_length = cnt;
1532 retval = send_xattr_stream(jcr, stream);
1535 * For a hard linked file we are ready now, no need to recursively save the attributes.
1541 * Store this hard linked file in the cache.
1542 * Store the name relative to the top level xattr space.
1544 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
1548 * Get any acl on the xattr.
1550 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
1555 * Encode the stat struct into an ASCII representation.
1557 encode_stat(attribs, &st, 0, stream);
1558 cnt = bsnprintf(buffer, sizeof(buffer),
1560 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1563 * Open the extended or extensible attribute file.
1565 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1568 retval = bxattr_exit_ok;
1571 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1572 target_attrname, jcr->last_fname, be.bstrerror());
1573 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1574 target_attrname, jcr->last_fname, be.bstrerror());
1581 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1582 * Encode the stat struct into an ASCII representation.
1584 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1587 retval = bxattr_exit_ok;
1590 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1591 target_attrname, jcr->last_fname, be.bstrerror());
1592 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1593 target_attrname, jcr->last_fname, be.bstrerror());
1599 * Generate a xattr encoding with the reference to the target in there.
1601 encode_stat(attribs, &st, st.st_ino, stream);
1602 cnt = bsnprintf(buffer, sizeof(buffer),
1604 target_attrname, 0, attribs, 0, link_source, 0);
1605 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1606 jcr->xattr_data->content_length = cnt;
1607 retval = send_xattr_stream(jcr, stream);
1609 if (retval == bxattr_exit_ok) {
1610 jcr->xattr_data->nr_saved++;
1614 * For a soft linked file we are ready now, no need to recursively save the attributes.
1622 * See if this is the first real xattr being saved.
1623 * If it is save the toplevel_hidden_dir attributes first.
1624 * This is easy as its stored already in the jcr->xattr_data->content buffer.
1626 if (jcr->xattr_data->nr_saved == 0) {
1627 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1628 if (retval != bxattr_exit_ok) {
1631 jcr->xattr_data->nr_saved++;
1634 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1635 jcr->xattr_data->content_length = cnt;
1638 * Only dump the content of regular files.
1640 switch (st.st_mode & S_IFMT) {
1642 if (st.st_size > 0) {
1644 * Protect ourself against things getting out of hand.
1646 if (st.st_size >= MAX_XATTR_STREAM) {
1647 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1648 jcr->last_fname, MAX_XATTR_STREAM);
1652 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1653 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
1654 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
1655 jcr->xattr_data->content_length += cnt;
1659 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
1660 target_attrname, jcr->last_fname);
1661 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1662 target_attrname, jcr->last_fname);
1673 retval = send_xattr_stream(jcr, stream);
1674 if (retval == bxattr_exit_ok) {
1675 jcr->xattr_data->nr_saved++;
1680 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1681 * available on this extended attribute.
1684 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1687 * The recursive call could change our working dir so change back to the wanted workdir.
1689 if (fchdir(fd) < 0) {
1692 retval = bxattr_exit_ok;
1695 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1696 jcr->last_fname, be.bstrerror());
1697 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1698 jcr->last_fname, fd, be.bstrerror());
1705 if (acl_text != NULL) {
1714 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1717 int fd, filefd = -1, attrdirfd = -1;
1720 char current_xattr_namespace[PATH_MAX];
1721 bxattr_exit_code retval = bxattr_exit_error;
1725 * Determine what argument to use. Use attr_parent when set
1726 * (recursive call) or jcr->last_fname for first call. Also save
1727 * the current depth of the xattr_space we are in.
1731 if (xattr_namespace) {
1732 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1733 xattr_namespace, attr_parent);
1735 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1738 name = jcr->last_fname;
1739 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1743 * Open the file on which to save the xattrs read-only.
1745 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1748 retval = bxattr_exit_ok;
1751 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1752 jcr->last_fname, be.bstrerror());
1753 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1754 jcr->last_fname, be.bstrerror());
1760 * Open the xattr naming space.
1762 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1766 * Gentile way of the system saying this type of xattr layering is not supported.
1767 * Which is not problem we just forget about this this xattr.
1768 * But as this is not an error we return a positive return value.
1770 retval = bxattr_exit_ok;
1773 retval = bxattr_exit_ok;
1776 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1777 name, jcr->last_fname, be.bstrerror());
1778 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1779 name, jcr->last_fname, be.bstrerror());
1785 * We need to change into the attribute directory to determine if each of the
1786 * attributes should be saved.
1788 if (fchdir(attrdirfd) < 0) {
1789 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1790 jcr->last_fname, be.bstrerror());
1791 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1792 jcr->last_fname, attrdirfd, be.bstrerror());
1797 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1798 * else because the readdir returns "." entry after the extensible attr entry.
1799 * And as we want this entry before anything else we better just save its data.
1802 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1803 true, STREAM_XATTR_SOLARIS);
1805 if ((fd = dup(attrdirfd)) == -1 ||
1806 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1807 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1808 jcr->last_fname, be.bstrerror());
1809 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1810 jcr->last_fname, fd, be.bstrerror());
1816 * Walk the namespace.
1818 while (dp = readdir(dirp)) {
1820 * Skip only the toplevel . dir.
1822 if (!attr_parent && bstrcmp(dp->d_name, "."))
1826 * Skip all .. directories
1828 if (bstrcmp(dp->d_name, ".."))
1831 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1832 current_xattr_namespace, dp->d_name, jcr->last_fname);
1834 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1836 * We are not interested in read-only extensible attributes.
1838 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
1839 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1840 current_xattr_namespace, dp->d_name, jcr->last_fname);
1846 * We are only interested in read-write extensible attributes
1847 * when they contain non-transient values.
1849 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
1851 * Determine if there are non-transient system attributes at the toplevel.
1852 * We need to provide a fd to the open file.
1854 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1855 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1856 current_xattr_namespace, dp->d_name, jcr->last_fname);
1863 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1864 false, STREAM_XATTR_SOLARIS_SYS);
1867 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1872 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1873 false, STREAM_XATTR_SOLARIS);
1877 retval = bxattr_exit_ok;
1880 if (attrdirfd != -1)
1888 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1890 #ifdef HAVE_EXTENDED_ACL
1895 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1896 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
1898 return bxattr_exit_error;
1901 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1902 acl_set(attrname, aclp) != 0) {
1903 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1904 attrname, jcr->last_fname, be.bstrerror());
1905 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1906 attrname, jcr->last_fname, be.bstrerror());
1907 return bxattr_exit_error;
1913 return bxattr_exit_ok;
1915 #else /* HAVE_EXTENDED_ACL */
1917 aclent_t *acls = NULL;
1920 acls = aclfromtext(acl_text, &n);
1922 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1923 acl(attrname, SETACL, n, acls) != 0) {
1924 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1925 attrname, jcr->last_fname, be.bstrerror());
1926 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1927 attrname, jcr->last_fname, be.bstrerror());
1928 return bxattr_exit_error;
1935 return bxattr_exit_ok;
1937 #endif /* HAVE_EXTENDED_ACL */
1940 #endif /* HAVE_ACL */
1942 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1944 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1945 int used_bytes, total_bytes, cnt;
1946 char *bp, *target_attrname, *attribs;
1947 char *linked_target = NULL;
1948 char *acl_text = NULL;
1952 struct timeval times[2];
1953 bxattr_exit_code retval = bxattr_exit_error;
1957 * Parse the xattr stream. First the part that is the same for all xattrs.
1960 total_bytes = jcr->xattr_data->content_length;
1963 * The name of the target xattr has a leading / we are not interested
1964 * in that so skip it when decoding the string. We always start a the /
1965 * of the xattr space anyway.
1967 target_attrname = jcr->xattr_data->content + 1;
1968 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1969 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1975 * Open the file on which to restore the xattrs read-only.
1977 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1978 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1979 jcr->last_fname, be.bstrerror());
1980 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1981 jcr->last_fname, be.bstrerror());
1986 * Open the xattr naming space and make it the current working dir.
1988 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1989 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1990 jcr->last_fname, be.bstrerror());
1991 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1992 jcr->last_fname, be.bstrerror());
1996 if (fchdir(attrdirfd) < 0) {
1997 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1998 jcr->last_fname, be.bstrerror());
1999 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2000 jcr->last_fname, attrdirfd, be.bstrerror());
2005 * Try to open the correct xattr subdir based on the target_attrname given.
2006 * e.g. check if its a subdir attrname. Each / in the string makes us go
2009 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2012 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2013 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2014 target_attrname, jcr->last_fname, be.bstrerror());
2015 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2016 target_attrname, jcr->last_fname, be.bstrerror());
2024 * Open the xattr naming space.
2026 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2027 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2028 target_attrname, jcr->last_fname, be.bstrerror());
2029 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2030 target_attrname, jcr->last_fname, be.bstrerror());
2038 * Make the xattr space our current workingdir.
2040 if (fchdir(attrdirfd) < 0) {
2041 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2042 target_attrname, jcr->last_fname, be.bstrerror());
2043 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2044 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2048 target_attrname = ++bp;
2052 * Decode the attributes from the stream.
2054 decode_stat(attribs, &st, &inum);
2057 * Decode the next field (acl_text).
2059 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2060 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2066 * Based on the filetype perform the correct action. We support most filetypes here, more
2067 * then the actual implementation on Solaris supports so some code may never get executed
2068 * due to limitations in the implementation.
2070 switch (st.st_mode & S_IFMT) {
2073 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2075 unlinkat(attrdirfd, target_attrname, 0);
2076 if (mkfifo(target_attrname, st.st_mode) < 0) {
2077 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
2078 target_attrname, jcr->last_fname, be.bstrerror());
2079 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
2080 target_attrname, jcr->last_fname, be.bstrerror());
2087 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2089 unlinkat(attrdirfd, target_attrname, 0);
2090 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
2091 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
2092 target_attrname, jcr->last_fname, be.bstrerror());
2093 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
2094 target_attrname, jcr->last_fname, be.bstrerror());
2100 * If its not the hidden_dir create the entry.
2101 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2103 if (!bstrcmp(target_attrname, ".")) {
2104 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
2105 if (mkdir(target_attrname, st.st_mode) < 0) {
2106 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
2107 target_attrname, jcr->last_fname, be.bstrerror());
2108 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
2109 target_attrname, jcr->last_fname, be.bstrerror());
2116 * See if this is a hard linked file. e.g. inum != 0
2121 unlinkat(attrdirfd, target_attrname, 0);
2122 if (link(linked_target, target_attrname) < 0) {
2123 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
2124 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2125 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
2126 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2131 * Successfully restored xattr.
2133 retval = bxattr_exit_ok;
2136 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
2137 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
2141 if (used_bytes < (total_bytes - 1))
2145 * Restore the actual xattr.
2147 if (!is_extensible) {
2148 unlinkat(attrdirfd, target_attrname, 0);
2151 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
2152 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2153 target_attrname, jcr->last_fname, be.bstrerror());
2154 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2155 target_attrname, jcr->last_fname, be.bstrerror());
2161 * Restore the actual data.
2163 if (st.st_size > 0) {
2164 used_bytes = (data - jcr->xattr_data->content);
2165 cnt = total_bytes - used_bytes;
2168 * Do a sanity check, the st.st_size should be the same as the number of bytes
2169 * we have available as data of the stream.
2171 if (cnt != st.st_size) {
2172 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
2173 target_attrname, jcr->last_fname);
2174 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
2175 target_attrname, jcr->last_fname);
2180 cnt = write(attrfd, data, cnt);
2182 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
2183 target_attrname, jcr->last_fname, be.bstrerror());
2184 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
2185 target_attrname, jcr->last_fname, be.bstrerror());
2191 cnt = total_bytes - used_bytes;
2197 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2201 if (symlink(linked_target, target_attrname) < 0) {
2202 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
2203 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2204 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
2205 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2210 * Successfully restored xattr.
2212 retval = bxattr_exit_ok;
2219 * Restore owner and acl for non extensible attributes.
2221 if (!is_extensible) {
2222 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
2226 * Gentile way of the system saying this type of xattr layering is not supported.
2227 * But as this is not an error we return a positive return value.
2229 retval = bxattr_exit_ok;
2232 retval = bxattr_exit_ok;
2235 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
2236 target_attrname, jcr->last_fname, be.bstrerror());
2237 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
2238 target_attrname, jcr->last_fname, be.bstrerror());
2245 if (acl_text && *acl_text)
2246 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
2248 #endif /* HAVE_ACL */
2251 * For a non extensible attribute restore access and modification time on the xattr.
2253 if (!is_extensible) {
2254 times[0].tv_sec = st.st_atime;
2255 times[0].tv_usec = 0;
2256 times[1].tv_sec = st.st_mtime;
2257 times[1].tv_usec = 0;
2259 if (futimesat(attrdirfd, target_attrname, times) < 0) {
2260 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
2261 target_attrname, jcr->last_fname, be.bstrerror());
2262 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
2263 target_attrname, jcr->last_fname, be.bstrerror());
2269 * Successfully restored xattr.
2271 retval = bxattr_exit_ok;
2275 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
2277 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
2284 if (attrdirfd != -1) {
2293 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2296 bxattr_exit_code retval = bxattr_exit_ok;
2299 * First see if extended attributes or extensible attributes are present.
2300 * If not just pretend things went ok.
2302 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
2303 jcr->xattr_data->nr_saved = 0;
2304 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
2307 * As we change the cwd in the save function save the current cwd
2308 * for restore after return from the solaris_save_xattrs function.
2310 getcwd(cwd, sizeof(cwd));
2311 retval = solaris_save_xattrs(jcr, NULL, NULL);
2313 delete jcr->xattr_data->link_cache;
2314 jcr->xattr_data->link_cache = NULL;
2319 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
2322 bool is_extensible = false;
2323 bxattr_exit_code retval;
2326 * First make sure we can restore xattr on the filesystem.
2329 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2330 case STREAM_XATTR_SOLARIS_SYS:
2331 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
2332 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
2333 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
2335 return bxattr_exit_error;
2338 is_extensible = true;
2341 case STREAM_XATTR_SOLARIS:
2342 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
2343 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
2344 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
2346 return bxattr_exit_error;
2350 return bxattr_exit_error;
2354 * As we change the cwd in the restore function save the current cwd
2355 * for restore after return from the solaris_restore_xattrs function.
2357 getcwd(cwd, sizeof(cwd));
2358 retval = solaris_restore_xattrs(jcr, is_extensible);
2365 * Function pointers to the build and parse function to use for these xattrs.
2367 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
2368 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
2370 #endif /* defined(HAVE_SUN_OS) */
2373 * Entry points when compiled with support for XATTRs on a supported platform.
2375 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2377 if (os_build_xattr_streams) {
2378 return (*os_build_xattr_streams)(jcr, ff_pkt);
2380 return bxattr_exit_error;
2383 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
2387 if (os_parse_xattr_streams) {
2389 * See if we can parse this stream, and ifso give it a try.
2391 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
2392 if (os_default_xattr_streams[cnt] == stream) {
2393 return (*os_parse_xattr_streams)(jcr, stream);
2398 * Issue a warning and discard the message. But pretend the restore was ok.
2400 Jmsg2(jcr, M_WARNING, 0,
2401 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
2402 jcr->last_fname, stream);
2403 return bxattr_exit_error;