2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2009 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Functions to handle Extended Attributes for bacula.
31 * Extended Attributes are so OS specific we only restore Extended Attributes if
32 * they were saved using a filed on the same platform.
34 * Currently we support the following OSes:
35 * - Darwin (Extended Attributes)
36 * - Linux (Extended Attributes)
37 * - NetBSD (Extended Attributes)
38 * - FreeBSD (Extended Attributes)
39 * - OpenBSD (Extended Attributes)
40 * - Solaris (Extended Attributes and Extensible Attributes)
42 * Written by Marco van Wieringen, November MMVIII
49 #if !defined(HAVE_XATTR)
51 * Entry points when compiled without support for XATTRs or on an unsupported platform.
53 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
55 return bxattr_exit_fatal;
58 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
60 return bxattr_exit_fatal;
64 * Send a XATTR stream to the SD.
66 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
68 BSOCK *sd = jcr->store_bsock;
70 #ifdef FD_NO_SEND_TEST
71 return bxattr_exit_ok;
77 if (jcr->xattr_data->content_length <= 0) {
78 return bxattr_exit_ok;
84 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
85 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
87 return bxattr_exit_fatal;
91 * Send the buffer to the storage deamon
93 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
95 sd->msg = jcr->xattr_data->content;
96 sd->msglen = jcr->xattr_data->content_length;
100 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
102 return bxattr_exit_fatal;
105 jcr->JobBytes += sd->msglen;
107 if (!sd->signal(BNET_EOD)) {
108 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
110 return bxattr_exit_fatal;
112 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
113 return bxattr_exit_ok;
117 * First some generic functions for OSes that use the same xattr encoding scheme.
119 #if defined(HAVE_DARWIN_OS) || \
120 defined(HAVE_LINUX_OS) || \
121 defined(HAVE_NETBSD_OS) || \
122 defined(HAVE_FREEBSD_OS) || \
123 defined(HAVE_OPENBSD_OS)
125 static void xattr_drop_internal_table(alist *xattr_value_list)
127 xattr_t *current_xattr;
130 * Walk the list of xattrs and free allocated memory on traversing.
132 foreach_alist(current_xattr, xattr_value_list) {
134 * See if we can shortcut.
136 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
139 free(current_xattr->name);
141 if (current_xattr->value_length > 0)
142 free(current_xattr->value);
145 delete xattr_value_list;
149 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
150 * which encodes one or more xattr_t structures.
152 * The Serialized stream consists of the following elements:
153 * magic - A magic string which makes it easy to detect any binary incompatabilites
154 * name_length - The length of the following xattr name
155 * name - The name of the extended attribute
156 * value_length - The length of the following xattr data
157 * value - The actual content of the extended attribute
159 * This is repeated 1 or more times.
162 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, alist *xattr_value_list)
164 xattr_t *current_xattr;
168 * Make sure the serialized stream fits in the poolmem buffer.
169 * We allocate some more to be sure the stream is gonna fit.
171 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
172 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
175 * Walk the list of xattrs and serialize the data.
177 foreach_alist(current_xattr, xattr_value_list) {
179 * See if we can shortcut.
181 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
184 ser_uint32(current_xattr->magic);
185 ser_uint32(current_xattr->name_length);
186 ser_bytes(current_xattr->name, current_xattr->name_length);
188 ser_uint32(current_xattr->value_length);
189 ser_bytes(current_xattr->value, current_xattr->value_length);
192 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
193 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
195 return jcr->xattr_data->content_length;
198 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
201 xattr_t *current_xattr;
202 bxattr_exit_code retval = bxattr_exit_ok;
205 * Parse the stream and call restore_xattr_on_file for each extended attribute.
207 * Start unserializing the data. We keep on looping while we have not
208 * unserialized all bytes in the stream.
210 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
211 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
213 * First make sure the magic is present. This way we can easily catch corruption.
214 * Any missing MAGIC is fatal we do NOT try to continue.
217 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
218 unser_uint32(current_xattr->magic);
219 if (current_xattr->magic != XATTR_MAGIC) {
220 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
222 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
225 return bxattr_exit_error;
229 * Decode the valuepair. First decode the length of the name.
231 unser_uint32(current_xattr->name_length);
234 * Allocate room for the name and decode its content.
236 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
237 unser_bytes(current_xattr->name, current_xattr->name_length);
240 * The xattr_name needs to be null terminated for lsetxattr.
242 current_xattr->name[current_xattr->name_length] = '\0';
245 * Decode the value length.
247 unser_uint32(current_xattr->value_length);
250 * Allocate room for the value and decode its content.
252 current_xattr->value = (char *)malloc(current_xattr->value_length);
253 unser_bytes(current_xattr->value, current_xattr->value_length);
255 xattr_value_list->append(current_xattr);
258 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
264 * This is a supported OS, See what kind of interface we should use.
266 #if defined(HAVE_DARWIN_OS) || \
267 defined(HAVE_LINUX_OS)
269 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
270 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
271 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
272 #error "Missing either full support for the LXATTR or XATTR functions."
275 #ifdef HAVE_SYS_XATTR_H
276 #include <sys/xattr.h>
278 #error "Missing sys/xattr.h header file"
282 * Define the supported XATTR streams for this OS
284 #if defined(HAVE_DARWIN_OS)
285 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
286 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
287 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
288 #elif defined(HAVE_LINUX_OS)
289 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
290 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
291 static const char *xattr_skiplist[1] = { NULL };
295 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
296 * listxattr, getxattr and setxattr with an extra options argument
297 * which mimics the l variants of the functions when we specify
298 * XATTR_NOFOLLOW as the options value.
300 #if defined(HAVE_DARWIN_OS)
301 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
302 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
303 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
306 * Fallback to the non l-functions when those are not available.
308 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
309 #define lgetxattr getxattr
311 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
312 #define lsetxattr setxattr
314 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
315 #define llistxattr listxattr
319 static bxattr_exit_code linux_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
322 char *xattr_list, *bp;
323 int cnt, xattr_count = 0;
324 int32_t xattr_list_len,
326 uint32_t expected_serialize_len = 0;
327 xattr_t *current_xattr;
328 alist *xattr_value_list = NULL;
329 bxattr_exit_code retval = bxattr_exit_error;
333 * First get the length of the available list with extended attributes.
335 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
336 if (xattr_list_len < 0) {
339 return bxattr_exit_ok;
341 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
342 jcr->last_fname, be.bstrerror());
343 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
344 jcr->last_fname, be.bstrerror());
345 return bxattr_exit_error;
347 } else if (xattr_list_len == 0) {
348 return bxattr_exit_ok;
352 * Allocate room for the extented attribute list.
354 xattr_list = (char *)malloc(xattr_list_len + 1);
355 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
358 * Get the actual list of extended attributes names for a file.
360 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
361 if (xattr_list_len < 0) {
364 retval = bxattr_exit_ok;
367 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
368 jcr->last_fname, be.bstrerror());
369 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
370 jcr->last_fname, be.bstrerror());
374 xattr_list[xattr_list_len] = '\0';
376 xattr_value_list = New(alist(10, not_owned_by_alist));
379 * Walk the list of extended attributes names and retrieve the data.
380 * We already count the bytes needed for serializing the stream later on.
383 while ((bp - xattr_list) + 1 < xattr_list_len) {
387 * On some OSes you also get the acls in the extented attribute list.
388 * So we check if we are already backing up acls and if we do we
389 * don't store the extended attribute with the same info.
391 if (ff_pkt->flags & FO_ACL) {
392 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
393 if (!strcmp(bp, xattr_acl_skiplist[cnt])) {
401 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
404 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
405 if (!strcmp(bp, xattr_skiplist[cnt])) {
413 bp = strchr(bp, '\0') + 1;
418 * Each xattr valuepair starts with a magic so we can parse it easier.
420 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
421 current_xattr->magic = XATTR_MAGIC;
422 expected_serialize_len += sizeof(current_xattr->magic);
425 * Allocate space for storing the name.
427 current_xattr->name_length = strlen(bp);
428 current_xattr->name = (char *)malloc(current_xattr->name_length);
429 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
431 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
434 * First see how long the value is for the extended attribute.
436 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
437 if (xattr_value_len < 0) {
440 retval = bxattr_exit_ok;
441 free(current_xattr->name);
445 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
446 jcr->last_fname, be.bstrerror());
447 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
448 jcr->last_fname, be.bstrerror());
449 free(current_xattr->name);
456 * Allocate space for storing the value.
458 current_xattr->value = (char *)malloc(xattr_value_len);
459 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
461 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
462 if (xattr_value_len < 0) {
465 retval = bxattr_exit_ok;
466 free(current_xattr->value);
467 free(current_xattr->name);
471 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
472 jcr->last_fname, be.bstrerror());
473 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
474 jcr->last_fname, be.bstrerror());
475 free(current_xattr->value);
476 free(current_xattr->name);
483 * Store the actual length of the value.
485 current_xattr->value_length = xattr_value_len;
486 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
489 * Protect ourself against things getting out of hand.
491 if (expected_serialize_len >= MAX_XATTR_STREAM) {
492 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
493 jcr->last_fname, MAX_XATTR_STREAM);
494 free(current_xattr->value);
495 free(current_xattr->name);
500 xattr_value_list->append(current_xattr);
502 bp = strchr(bp, '\0') + 1;
506 xattr_list = (char *)NULL;
509 * If we found any xattr send them to the SD.
511 if (xattr_count > 0) {
513 * Serialize the datastream.
515 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
516 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
518 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
523 xattr_drop_internal_table(xattr_value_list);
526 * Send the datastream to the SD.
528 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
530 xattr_drop_internal_table(xattr_value_list);
532 return bxattr_exit_ok;
539 if (xattr_value_list) {
540 xattr_drop_internal_table(xattr_value_list);
545 static bxattr_exit_code linux_xattr_parse_streams(JCR *jcr, int stream)
547 xattr_t *current_xattr;
548 alist *xattr_value_list;
551 xattr_value_list = New(alist(10, not_owned_by_alist));
553 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
554 xattr_drop_internal_table(xattr_value_list);
555 return bxattr_exit_error;
558 foreach_alist(current_xattr, xattr_value_list) {
559 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
564 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
565 jcr->last_fname, be.bstrerror());
566 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
567 jcr->last_fname, be.bstrerror());
573 xattr_drop_internal_table(xattr_value_list);
574 return bxattr_exit_ok;
577 xattr_drop_internal_table(xattr_value_list);
578 return bxattr_exit_error;
582 * Function pointers to the build and parse function to use for these xattrs.
584 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = linux_xattr_build_streams;
585 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = linux_xattr_parse_streams;
587 #elif defined(HAVE_FREEBSD_OS) || \
588 defined(HAVE_NETBSD_OS) || \
589 defined(HAVE_OPENBSD_OS)
591 #if !defined(HAVE_EXTATTR_GET_LINK) || \
592 !defined(HAVE_EXTATTR_SET_LINK) || \
593 !defined(HAVE_EXTATTR_LIST_LINK) || \
594 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
595 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
596 #error "Missing full support for the extattr functions."
599 #ifdef HAVE_SYS_EXTATTR_H
600 #include <sys/extattr.h>
602 #error "Missing sys/extattr.h header file"
605 #ifdef HAVE_LIBUTIL_H
609 #if defined(HAVE_FREEBSD_OS)
610 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
611 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
612 static const char *xattr_acl_skiplist[1] = { NULL };
613 static const char *xattr_skiplist[1] = { NULL };
614 #elif defined(HAVE_NETBSD_OS)
615 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
616 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
617 static const char *xattr_acl_skiplist[1] = { NULL };
618 static const char *xattr_skiplist[1] = { NULL };
619 #elif defined(HAVE_OPENBSD_OS)
620 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
621 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
622 static const char *xattr_acl_skiplist[1] = { NULL };
623 static const char *xattr_skiplist[1] = { NULL };
626 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
630 int cnt, index, xattr_count = 0;
631 int32_t xattr_list_len,
633 uint32_t expected_serialize_len = 0;
634 unsigned int namespace_index;
636 char *current_attrnamespace, current_attrname[BUFSIZ], current_attrtuple[BUFSIZ];
637 xattr_t *current_xattr;
638 alist *xattr_value_list = NULL;
639 bxattr_exit_code retval = bxattr_exit_error;
642 xattr_value_list = New(alist(10, not_owned_by_alist));
645 * Loop over all available xattr namespaces.
647 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
648 attrnamespace = os_default_xattr_namespaces[namespace_index];
651 * First get the length of the available list with extended attributes.
653 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
654 if (xattr_list_len < 0) {
657 retval = bxattr_exit_ok;
660 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
661 jcr->last_fname, be.bstrerror());
662 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
663 jcr->last_fname, be.bstrerror());
666 } else if (xattr_list_len == 0) {
671 * Allocate room for the extented attribute list.
673 xattr_list = (char *)malloc(xattr_list_len + 1);
674 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
677 * Get the actual list of extended attributes names for a file.
679 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
680 if (xattr_list_len < 0) {
683 retval = bxattr_exit_ok;
686 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
687 jcr->last_fname, be.bstrerror());
688 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
689 jcr->last_fname, be.bstrerror());
693 xattr_list[xattr_list_len] = '\0';
696 * Walk the list of extended attributes names and retrieve the data.
697 * We already count the bytes needed for serializing the stream later on.
699 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
701 bsnprintf(current_attrname, sizeof(current_attrname), "%*.*s",
702 xattr_list[index], xattr_list[index], xattr_list + (index + 1));
705 * First make a xattr tuple of the current namespace and the name of the xattr.
706 * e.g. something like user.<attrname> or system.<attrname>
708 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
709 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
710 attrnamespace, jcr->last_fname);
711 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
712 attrnamespace, jcr->last_fname);
717 * print the current name into the buffer as its not null terminated we need to
718 * use the length encoded in the string for copying only the needed bytes.
720 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
723 * On some OSes you also get the acls in the extented attribute list.
724 * So we check if we are already backing up acls and if we do we
725 * don't store the extended attribute with the same info.
727 if (ff_pkt->flags & FO_ACL) {
728 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
729 if (!strcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
737 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
740 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
741 if (!strcmp(current_attrtuple, xattr_skiplist[cnt])) {
753 * Each xattr valuepair starts with a magic so we can parse it easier.
755 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
756 current_xattr->magic = XATTR_MAGIC;
757 expected_serialize_len += sizeof(current_xattr->magic);
760 * Allocate space for storing the name.
762 current_xattr->name_length = strlen(current_attrtuple);
763 current_xattr->name = (char *)malloc(current_xattr->name_length);
764 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
766 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
769 * First see how long the value is for the extended attribute.
771 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
772 if (xattr_value_len < 0) {
775 retval = bxattr_exit_ok;
776 free(current_xattr->name);
780 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
781 jcr->last_fname, be.bstrerror());
782 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
783 jcr->last_fname, be.bstrerror());
784 free(current_xattr->name);
791 * Allocate space for storing the value.
793 current_xattr->value = (char *)malloc(xattr_value_len);
794 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
796 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
797 if (xattr_value_len < 0) {
800 retval = bxattr_exit_ok;
801 free(current_xattr->value);
802 free(current_xattr->name);
806 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
807 jcr->last_fname, be.bstrerror());
808 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
809 jcr->last_fname, be.bstrerror());
810 free(current_xattr->value);
811 free(current_xattr->name);
818 * Store the actual length of the value.
820 current_xattr->value_length = xattr_value_len;
821 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
824 * Protect ourself against things getting out of hand.
826 if (expected_serialize_len >= MAX_XATTR_STREAM) {
827 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
828 jcr->last_fname, MAX_XATTR_STREAM);
829 free(current_xattr->value);
830 free(current_xattr->name);
835 xattr_value_list->append(current_xattr);
840 * We are done with this xattr list.
843 xattr_list = (char *)NULL;
847 * If we found any xattr send them to the SD.
849 if (xattr_count > 0) {
851 * Serialize the datastream.
853 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
854 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
856 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
861 xattr_drop_internal_table(xattr_value_list);
862 xattr_value_list = NULL;
865 * Send the datastream to the SD.
867 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
869 xattr_drop_internal_table(xattr_value_list);
870 xattr_value_list = NULL;
872 return bxattr_exit_ok;
879 if (xattr_value_list) {
880 xattr_drop_internal_table(xattr_value_list);
881 xattr_value_list = NULL;
886 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
888 xattr_t *current_xattr;
889 alist *xattr_value_list;
890 int current_attrnamespace, cnt;
891 char *attrnamespace, *attrname;
894 xattr_value_list = New(alist(10, not_owned_by_alist));
896 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
897 xattr_drop_internal_table(xattr_value_list);
898 return bxattr_exit_error;
901 foreach_alist(current_xattr, xattr_value_list) {
903 * Try splitting the xattr_name into a namespace and name part.
904 * The splitting character is a .
906 attrnamespace = current_xattr->name;
907 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
908 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
909 current_xattr->name, jcr->last_fname);
910 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
911 current_xattr->name, jcr->last_fname);
917 * Make sure the attrnamespace makes sense.
919 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
920 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
921 attrnamespace, jcr->last_fname);
922 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
923 attrnamespace, jcr->last_fname);
928 * Try restoring the extended attribute.
930 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
931 attrname, current_xattr->value, current_xattr->value_length);
932 if (cnt < 0 || cnt != current_xattr->value_length) {
938 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
939 jcr->last_fname, be.bstrerror());
940 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
941 jcr->last_fname, be.bstrerror());
948 xattr_drop_internal_table(xattr_value_list);
949 return bxattr_exit_ok;
952 xattr_drop_internal_table(xattr_value_list);
953 return bxattr_exit_error;
957 * Function pointers to the build and parse function to use for these xattrs.
959 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
960 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
962 #elif defined(HAVE_SUN_OS)
964 * Solaris extended attributes were introduced in Solaris 9
967 * Solaris extensible attributes were introduced in OpenSolaris
968 * by PSARC 2007/315 Solaris extensible attributes are also
969 * sometimes called extended system attributes.
971 * man fsattr(5) on Solaris gives a wealth of info. The most
972 * important bits are:
974 * Attributes are logically supported as files within the file
975 * system. The file system is therefore augmented with an
976 * orthogonal name space of file attributes. Any file (includ-
977 * ing attribute files) can have an arbitrarily deep attribute
978 * tree associated with it. Attribute values are accessed by
979 * file descriptors obtained through a special attribute inter-
980 * face. This logical view of "attributes as files" allows the
981 * leveraging of existing file system interface functionality
982 * to support the construction, deletion, and manipulation of
985 * The special files "." and ".." retain their accustomed
986 * semantics within the attribute hierarchy. The "." attribute
987 * file refers to the current directory and the ".." attribute
988 * file refers to the parent directory. The unnamed directory
989 * at the head of each attribute tree is considered the "child"
990 * of the file it is associated with and the ".." file refers
991 * to the associated file. For any non-directory file with
992 * attributes, the ".." entry in the unnamed directory refers
993 * to a file that is not a directory.
995 * Conceptually, the attribute model is fully general. Extended
996 * attributes can be any type of file (doors, links, direc-
997 * tories, and so forth) and can even have their own attributes
998 * (fully recursive). As a result, the attributes associated
999 * with a file could be an arbitrarily deep directory hierarchy
1000 * where each attribute could have an equally complex attribute
1001 * tree associated with it. Not all implementations are able
1002 * to, or want to, support the full model. Implementation are
1003 * therefore permitted to reject operations that are not sup-
1004 * ported. For example, the implementation for the UFS file
1005 * system allows only regular files as attributes (for example,
1006 * no sub-directories) and rejects attempts to place attributes
1009 * The following list details the operations that are rejected
1010 * in the current implementation:
1012 * link Any attempt to create links between
1013 * attribute and non-attribute space
1014 * is rejected to prevent security-
1015 * related or otherwise sensitive
1016 * attributes from being exposed, and
1017 * therefore manipulable, as regular
1020 * rename Any attempt to rename between
1021 * attribute and non-attribute space
1022 * is rejected to prevent an already
1023 * linked file from being renamed and
1024 * thereby circumventing the link res-
1027 * mkdir, symlink, mknod Any attempt to create a "non-
1028 * regular" file in attribute space is
1029 * rejected to reduce the functional-
1030 * ity, and therefore exposure and
1031 * risk, of the initial implementa-
1034 * The entire available name space has been allocated to "gen-
1035 * eral use" to bring the implementation in line with the NFSv4
1036 * draft standard [NFSv4]. That standard defines "named attri-
1037 * butes" (equivalent to Solaris Extended Attributes) with no
1038 * naming restrictions. All Sun applications making use of
1039 * opaque extended attributes will use the prefix "SUNW".
1042 #ifdef HAVE_SYS_ATTR_H
1043 #include <sys/attr.h>
1050 #ifdef HAVE_SYS_NVPAIR_H
1051 #include <sys/nvpair.h>
1054 #ifdef HAVE_SYS_ACL_H
1055 #include <sys/acl.h>
1058 #if !defined(HAVE_OPENAT) ||
1059 !defined(HAVE_UNKINKAT) ||
1060 !defined(HAVE_FCHOWNAT) ||
1061 !defined(HAVE_FUTIMESAT)
1062 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
1066 * Define the supported XATTR streams for this OS
1068 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1069 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
1071 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
1072 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
1075 * This code creates a temporary cache with entries for each xattr which has
1076 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
1078 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
1080 xattr_link_cache_entry_t *ptr;
1082 foreach_alist(ptr, jcr->xattr_data->link_cache) {
1083 if (ptr && ptr->inum == inum) {
1090 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
1092 xattr_link_cache_entry_t *ptr;
1094 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
1095 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
1097 bstrncpy(ptr->target, target, sizeof(ptr->target));
1098 jcr->xattr_data->link_cache->append(ptr);
1101 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1103 * This function returns true if a non default extended system attribute
1104 * list is associated with fd and returns false when an error has occured
1105 * or when only extended system attributes other than archive,
1106 * av_modified or crtime are set.
1108 * The function returns true for the following cases:
1110 * - any extended system attribute other than the default attributes
1111 * ('archive', 'av_modified' and 'crtime') is set
1112 * - nvlist has NULL name string
1113 * - nvpair has data type of 'nvlist'
1114 * - default data type.
1116 static bool solaris_has_non_transient_extensible_attributes(int fd)
1124 bool retval = false;
1126 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
1131 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
1132 name = nvpair_name(pair);
1135 fattr = name_to_attr(name);
1141 type = nvpair_type(pair);
1143 case DATA_TYPE_BOOLEAN_VALUE:
1144 if (nvpair_value_boolean_value(pair, &value) != 0) {
1147 if (value && fattr != F_ARCHIVE &&
1148 fattr != F_AV_MODIFIED) {
1153 case DATA_TYPE_UINT64_ARRAY:
1154 if (fattr != F_CRTIME) {
1159 case DATA_TYPE_NVLIST:
1167 if (response != NULL) {
1168 nvlist_free(response);
1172 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1174 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
1176 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
1177 * There is no need to store those acls as we already store the stat bits too.
1179 static bool acl_is_trivial(int count, aclent_t *entries)
1184 for (n = 0; n < count; n++) {
1186 if (!(ace->a_type == USER_OBJ ||
1187 ace->a_type == GROUP_OBJ ||
1188 ace->a_type == OTHER_OBJ ||
1189 ace->a_type == CLASS_OBJ))
1194 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
1196 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
1199 #ifdef HAVE_EXTENDED_ACL
1205 * See if this attribute has an ACL
1207 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
1208 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
1210 * See if there is a non trivial acl on the file.
1212 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
1213 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
1216 return bxattr_exit_ok;
1218 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1219 attrname, jcr->last_fname, be.bstrerror());
1220 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
1221 attrname, jcr->last_fname, be.bstrerror());
1222 return bxattr_exit_error;
1227 #if defined(ACL_SID_FMT)
1229 * New format flag added in newer Solaris versions.
1231 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
1233 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
1234 #endif /* ACL_SID_FMT */
1236 *acl_text = acl_totext(aclp, flags);
1244 return bxattr_exit_ok;
1245 #else /* HAVE_EXTENDED_ACL */
1247 aclent_t *acls = NULL;
1251 * See if this attribute has an ACL
1254 n = facl(fd, GETACLCNT, 0, NULL);
1256 n = acl(attrname, GETACLCNT, 0, NULL);
1259 if (n >= MIN_ACL_ENTRIES) {
1260 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
1261 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
1262 acl(attrname, GETACL, n, acls) != n) {
1266 return bxattr_exit_ok;
1268 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
1269 attrname, jcr->last_fname, be.bstrerror());
1270 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
1271 attrname, jcr->last_fname, be.bstrerror());
1273 return bxattr_exit_error;
1278 * See if there is a non trivial acl on the file.
1280 if (!acl_is_trivial(n, acls)) {
1281 if ((*acl_text = acltotext(acls, n)) == NULL) {
1282 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
1283 attrname, jcr->last_fname, be.bstrerror());
1284 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
1285 attrname, jcr->last_fname, be.bstrerror());
1287 return bxattr_exit_error;
1297 return bxattr_exit_ok;
1298 #endif /* HAVE_EXTENDED_ACL */
1300 #else /* HAVE_ACL */
1301 return bxattr_exit_ok;
1302 #endif /* HAVE_ACL */
1306 * Forward declaration for recursive function call.
1308 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
1311 * Save an extended or extensible attribute.
1312 * This is stored as an opaque stream of bytes with the following encoding:
1314 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
1316 * or for a hardlinked or symlinked attribute
1318 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
1320 * xattr_name can be a subpath relative to the file the xattr is on.
1321 * stat_buffer is the string representation of the stat struct.
1322 * acl_string is an acl text when a non trivial acl is set on the xattr.
1323 * actual_xattr_data is the content of the xattr file.
1325 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
1326 const char *attrname, bool toplevel_hidden_dir, int stream)
1331 xattr_link_cache_entry_t *xlce;
1332 char target_attrname[PATH_MAX];
1333 char link_source[PATH_MAX];
1334 char *acl_text = NULL;
1335 char attribs[MAXSTRING];
1336 char buffer[BUFSIZ];
1337 bxattr_exit_code retval = bxattr_exit_error;
1340 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
1343 * Get the stats of the extended or extensible attribute.
1345 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
1348 retval = bxattr_exit_ok;
1351 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
1352 target_attrname, jcr->last_fname, be.bstrerror());
1353 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
1354 target_attrname, jcr->last_fname, be.bstrerror());
1360 * Based on the filetype perform the correct action. We support most filetypes here, more
1361 * then the actual implementation on Solaris supports so some code may never get executed
1362 * due to limitations in the implementation.
1364 switch (st.st_mode & S_IFMT) {
1369 * Get any acl on the xattr.
1371 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1375 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1376 * Encode the stat struct into an ASCII representation.
1378 encode_stat(attribs, &st, 0, stream);
1379 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
1380 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1384 * Get any acl on the xattr.
1386 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1390 * See if this is the toplevel_hidden_dir being saved.
1392 if (toplevel_hidden_dir) {
1394 * Save the data for later storage when we encounter a real xattr. We store the data
1395 * in the jcr->xattr_data->content buffer and flush that just before sending out the
1396 * first real xattr. Encode the stat struct into an ASCII representation and jump
1397 * out of the function.
1399 encode_stat(attribs, &st, 0, stream);
1400 cnt = bsnprintf(buffer, sizeof(buffer),
1402 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1403 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1404 jcr->xattr_data->content_length = cnt;
1408 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1409 * Encode the stat struct into an ASCII representation.
1411 encode_stat(attribs, &st, 0, stream);
1412 cnt = bsnprintf(buffer, sizeof(buffer),
1414 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1419 * If this is a hardlinked file check the inode cache for a hit.
1421 if (st.st_nlink > 1) {
1423 * See if the cache already knows this inode number.
1425 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
1427 * Generate a xattr encoding with the reference to the target in there.
1429 encode_stat(attribs, &st, st.st_ino, stream);
1430 cnt = bsnprintf(buffer, sizeof(buffer),
1432 target_attrname, 0, attribs, 0, xlce->target, 0);
1433 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1434 jcr->xattr_data->content_length = cnt;
1435 retval = send_xattr_stream(jcr, stream);
1438 * For a hard linked file we are ready now, no need to recursively save the attributes.
1444 * Store this hard linked file in the cache.
1445 * Store the name relative to the top level xattr space.
1447 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
1451 * Get any acl on the xattr.
1453 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
1458 * Encode the stat struct into an ASCII representation.
1460 encode_stat(attribs, &st, 0, stream);
1461 cnt = bsnprintf(buffer, sizeof(buffer),
1463 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1466 * Open the extended or extensible attribute file.
1468 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1471 retval = bxattr_exit_ok;
1474 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1475 target_attrname, jcr->last_fname, be.bstrerror());
1476 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1477 target_attrname, jcr->last_fname, be.bstrerror());
1484 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1485 * Encode the stat struct into an ASCII representation.
1487 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1490 retval = bxattr_exit_ok;
1493 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1494 target_attrname, jcr->last_fname, be.bstrerror());
1495 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1496 target_attrname, jcr->last_fname, be.bstrerror());
1502 * Generate a xattr encoding with the reference to the target in there.
1504 encode_stat(attribs, &st, st.st_ino, stream);
1505 cnt = bsnprintf(buffer, sizeof(buffer),
1507 target_attrname, 0, attribs, 0, link_source, 0);
1508 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1509 jcr->xattr_data->content_length = cnt;
1510 retval = send_xattr_stream(jcr, stream);
1512 if (retval == bxattr_exit_ok) {
1513 jcr->xattr_data->nr_saved++;
1517 * For a soft linked file we are ready now, no need to recursively save the attributes.
1525 * See if this is the first real xattr being saved.
1526 * If it is save the toplevel_hidden_dir attributes first.
1527 * This is easy as its stored already in the jcr->xattr_data->content buffer.
1529 if (jcr->xattr_data->nr_saved == 0) {
1530 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1531 if (retval != bxattr_exit_ok) {
1534 jcr->xattr_data->nr_saved++;
1537 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1538 jcr->xattr_data->content_length = cnt;
1541 * Only dump the content of regular files.
1543 switch (st.st_mode & S_IFMT) {
1545 if (st.st_size > 0) {
1547 * Protect ourself against things getting out of hand.
1549 if (st.st_size >= MAX_XATTR_STREAM) {
1550 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1551 jcr->last_fname, MAX_XATTR_STREAM);
1555 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1556 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
1557 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
1558 jcr->xattr_data->content_length += cnt;
1562 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
1563 target_attrname, jcr->last_fname);
1564 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1565 target_attrname, jcr->last_fname);
1576 retval = send_xattr_stream(jcr, stream);
1577 if (retval == bxattr_exit_ok) {
1578 jcr->xattr_data->nr_saved++;
1583 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1584 * available on this extended attribute.
1587 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1590 * The recursive call could change our working dir so change back to the wanted workdir.
1592 if (fchdir(fd) < 0) {
1595 retval = bxattr_exit_ok;
1598 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1599 jcr->last_fname, be.bstrerror());
1600 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1601 jcr->last_fname, fd, be.bstrerror());
1617 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1620 int fd, filefd = -1, attrdirfd = -1;
1623 char current_xattr_namespace[PATH_MAX];
1624 bxattr_exit_code retval = bxattr_exit_error;
1628 * Determine what argument to use. Use attr_parent when set
1629 * (recursive call) or jcr->last_fname for first call. Also save
1630 * the current depth of the xattr_space we are in.
1634 if (xattr_namespace) {
1635 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1636 xattr_namespace, attr_parent);
1638 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1641 name = jcr->last_fname;
1642 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1646 * Open the file on which to save the xattrs read-only.
1648 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1651 retval = bxattr_exit_ok;
1654 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1655 jcr->last_fname, be.bstrerror());
1656 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1657 jcr->last_fname, be.bstrerror());
1663 * Open the xattr naming space.
1665 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1669 * Gentile way of the system saying this type of xattr layering is not supported.
1670 * Which is not problem we just forget about this this xattr.
1671 * But as this is not an error we return a positive return value.
1673 retval = bxattr_exit_ok;
1676 retval = bxattr_exit_ok;
1679 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1680 name, jcr->last_fname, be.bstrerror());
1681 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1682 name, jcr->last_fname, be.bstrerror());
1688 * We need to change into the attribute directory to determine if each of the
1689 * attributes should be saved.
1691 if (fchdir(attrdirfd) < 0) {
1692 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1693 jcr->last_fname, be.bstrerror());
1694 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1695 jcr->last_fname, attrdirfd, be.bstrerror());
1700 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1701 * else because the readdir returns "." entry after the extensible attr entry.
1702 * And as we want this entry before anything else we better just save its data.
1705 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1706 true, STREAM_XATTR_SOLARIS);
1708 if ((fd = dup(attrdirfd)) == -1 ||
1709 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1710 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1711 jcr->last_fname, be.bstrerror());
1712 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1713 jcr->last_fname, fd, be.bstrerror());
1719 * Walk the namespace.
1721 while (dp = readdir(dirp)) {
1723 * Skip only the toplevel . dir.
1725 if (!attr_parent && !strcmp(dp->d_name, "."))
1729 * Skip all .. directories
1731 if (!strcmp(dp->d_name, ".."))
1734 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1735 current_xattr_namespace, dp->d_name, jcr->last_fname);
1737 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1739 * We are not interested in read-only extensible attributes.
1741 if (!strcmp(dp->d_name, VIEW_READONLY)) {
1742 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1743 current_xattr_namespace, dp->d_name, jcr->last_fname);
1749 * We are only interested in read-write extensible attributes
1750 * when they contain non-transient values.
1752 if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1754 * Determine if there are non-transient system attributes at the toplevel.
1755 * We need to provide a fd to the open file.
1757 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1758 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1759 current_xattr_namespace, dp->d_name, jcr->last_fname);
1766 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1767 false, STREAM_XATTR_SOLARIS_SYS);
1770 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1775 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1776 false, STREAM_XATTR_SOLARIS);
1780 retval = bxattr_exit_ok;
1783 if (attrdirfd != -1)
1791 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1793 #ifdef HAVE_EXTENDED_ACL
1798 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1799 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
1801 return bxattr_exit_error;
1804 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1805 acl_set(attrname, aclp) != 0) {
1806 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1807 attrname, jcr->last_fname, be.bstrerror());
1808 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1809 attrname, jcr->last_fname, be.bstrerror());
1810 return bxattr_exit_error;
1816 return bxattr_exit_ok;
1818 #else /* HAVE_EXTENDED_ACL */
1820 aclent_t *acls = NULL;
1823 acls = aclfromtext(acl_text, &n);
1825 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1826 acl(attrname, SETACL, n, acls) != 0) {
1827 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1828 attrname, jcr->last_fname, be.bstrerror());
1829 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1830 attrname, jcr->last_fname, be.bstrerror());
1831 return bxattr_exit_error;
1838 return bxattr_exit_ok;
1840 #endif /* HAVE_EXTENDED_ACL */
1843 #endif /* HAVE_ACL */
1845 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1847 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1848 int used_bytes, total_bytes, cnt;
1849 char *bp, *target_attrname, *attribs;
1850 char *linked_target = NULL;
1851 char *acl_text = NULL;
1855 struct timeval times[2];
1856 bxattr_exit_code retval = bxattr_exit_error;
1860 * Parse the xattr stream. First the part that is the same for all xattrs.
1863 total_bytes = jcr->xattr_data->content_length;
1866 * The name of the target xattr has a leading / we are not interested
1867 * in that so skip it when decoding the string. We always start a the /
1868 * of the xattr space anyway.
1870 target_attrname = jcr->xattr_data->content + 1;
1871 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1872 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1878 * Open the file on which to restore the xattrs read-only.
1880 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1881 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1882 jcr->last_fname, be.bstrerror());
1883 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1884 jcr->last_fname, be.bstrerror());
1889 * Open the xattr naming space and make it the current working dir.
1891 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1892 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1893 jcr->last_fname, be.bstrerror());
1894 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1895 jcr->last_fname, be.bstrerror());
1899 if (fchdir(attrdirfd) < 0) {
1900 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1901 jcr->last_fname, be.bstrerror());
1902 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1903 jcr->last_fname, attrdirfd, be.bstrerror());
1908 * Try to open the correct xattr subdir based on the target_attrname given.
1909 * e.g. check if its a subdir attrname. Each / in the string makes us go
1912 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1915 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1916 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1917 target_attrname, jcr->last_fname, be.bstrerror());
1918 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1919 target_attrname, jcr->last_fname, be.bstrerror());
1927 * Open the xattr naming space.
1929 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1930 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1931 target_attrname, jcr->last_fname, be.bstrerror());
1932 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1933 target_attrname, jcr->last_fname, be.bstrerror());
1941 * Make the xattr space our current workingdir.
1943 if (fchdir(attrdirfd) < 0) {
1944 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1945 target_attrname, jcr->last_fname, be.bstrerror());
1946 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1947 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1951 target_attrname = ++bp;
1955 * Decode the attributes from the stream.
1957 decode_stat(attribs, &st, &inum);
1960 * Decode the next field (acl_text).
1962 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1963 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1969 * Based on the filetype perform the correct action. We support most filetypes here, more
1970 * then the actual implementation on Solaris supports so some code may never get executed
1971 * due to limitations in the implementation.
1973 switch (st.st_mode & S_IFMT) {
1976 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1978 unlinkat(attrdirfd, target_attrname, 0);
1979 if (mkfifo(target_attrname, st.st_mode) < 0) {
1980 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1981 target_attrname, jcr->last_fname, be.bstrerror());
1982 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1983 target_attrname, jcr->last_fname, be.bstrerror());
1990 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1992 unlinkat(attrdirfd, target_attrname, 0);
1993 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1994 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1995 target_attrname, jcr->last_fname, be.bstrerror());
1996 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1997 target_attrname, jcr->last_fname, be.bstrerror());
2003 * If its not the hidden_dir create the entry.
2004 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2006 if (strcmp(target_attrname, ".")) {
2007 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
2008 if (mkdir(target_attrname, st.st_mode) < 0) {
2009 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
2010 target_attrname, jcr->last_fname, be.bstrerror());
2011 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
2012 target_attrname, jcr->last_fname, be.bstrerror());
2019 * See if this is a hard linked file. e.g. inum != 0
2024 unlinkat(attrdirfd, target_attrname, 0);
2025 if (link(linked_target, target_attrname) < 0) {
2026 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
2027 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2028 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
2029 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2034 * Successfully restored xattr.
2036 retval = bxattr_exit_ok;
2039 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
2040 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
2044 if (used_bytes < (total_bytes - 1))
2048 * Restore the actual xattr.
2050 if (!is_extensible) {
2051 unlinkat(attrdirfd, target_attrname, 0);
2054 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
2055 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2056 target_attrname, jcr->last_fname, be.bstrerror());
2057 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2058 target_attrname, jcr->last_fname, be.bstrerror());
2064 * Restore the actual data.
2066 if (st.st_size > 0) {
2067 used_bytes = (data - jcr->xattr_data->content);
2068 cnt = total_bytes - used_bytes;
2071 * Do a sanity check, the st.st_size should be the same as the number of bytes
2072 * we have available as data of the stream.
2074 if (cnt != st.st_size) {
2075 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
2076 target_attrname, jcr->last_fname);
2077 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
2078 target_attrname, jcr->last_fname);
2083 cnt = write(attrfd, data, cnt);
2085 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
2086 target_attrname, jcr->last_fname, be.bstrerror());
2087 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
2088 target_attrname, jcr->last_fname, be.bstrerror());
2094 cnt = total_bytes - used_bytes;
2100 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2104 if (symlink(linked_target, target_attrname) < 0) {
2105 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
2106 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2107 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
2108 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
2113 * Successfully restored xattr.
2115 retval = bxattr_exit_ok;
2122 * Restore owner and acl for non extensible attributes.
2124 if (!is_extensible) {
2125 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
2129 * Gentile way of the system saying this type of xattr layering is not supported.
2130 * But as this is not an error we return a positive return value.
2132 retval = bxattr_exit_ok;
2135 retval = bxattr_exit_ok;
2138 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
2139 target_attrname, jcr->last_fname, be.bstrerror());
2140 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
2141 target_attrname, jcr->last_fname, be.bstrerror());
2148 if (acl_text && *acl_text)
2149 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
2151 #endif /* HAVE_ACL */
2154 * For a non extensible attribute restore access and modification time on the xattr.
2156 if (!is_extensible) {
2157 times[0].tv_sec = st.st_atime;
2158 times[0].tv_usec = 0;
2159 times[1].tv_sec = st.st_mtime;
2160 times[1].tv_usec = 0;
2162 if (futimesat(attrdirfd, target_attrname, times) < 0) {
2163 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
2164 target_attrname, jcr->last_fname, be.bstrerror());
2165 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
2166 target_attrname, jcr->last_fname, be.bstrerror());
2172 * Successfully restored xattr.
2174 retval = bxattr_exit_ok;
2178 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
2180 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
2187 if (attrdirfd != -1) {
2196 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2199 bxattr_exit_code retval = bxattr_exit_ok;
2202 * First see if extended attributes or extensible attributes are present.
2203 * If not just pretend things went ok.
2205 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
2206 jcr->xattr_data->nr_saved = 0;
2207 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
2210 * As we change the cwd in the save function save the current cwd
2211 * for restore after return from the solaris_save_xattrs function.
2213 getcwd(cwd, sizeof(cwd));
2214 retval = solaris_save_xattrs(jcr, NULL, NULL);
2216 delete jcr->xattr_data->link_cache;
2217 jcr->xattr_data->link_cache = NULL;
2222 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
2225 bool is_extensible = false;
2226 bxattr_exit_code retval;
2229 * First make sure we can restore xattr on the filesystem.
2232 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2233 case STREAM_XATTR_SOLARIS_SYS:
2234 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
2235 Qmsg1(jcr, M_WARNING, 0,
2236 _("Failed to restore extensible attributes on file \"%s\"\n"),
2238 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
2240 return bxattr_exit_error;
2243 is_extensible = true;
2246 case STREAM_XATTR_SOLARIS:
2247 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
2248 Qmsg1(jcr, M_WARNING, 0,
2249 _("Failed to restore extended attributes on file \"%s\"\n"),
2251 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
2253 return bxattr_exit_error;
2257 return bxattr_exit_error;
2261 * As we change the cwd in the restore function save the current cwd
2262 * for restore after return from the solaris_restore_xattrs function.
2264 getcwd(cwd, sizeof(cwd));
2265 retval = solaris_restore_xattrs(jcr, is_extensible);
2272 * Function pointers to the build and parse function to use for these xattrs.
2274 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
2275 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
2277 #endif /* defined(HAVE_SUN_OS) */
2280 * Entry points when compiled with support for XATTRs on a supported platform.
2282 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
2284 if (os_build_xattr_streams) {
2285 return (*os_build_xattr_streams)(jcr, ff_pkt);
2287 return bxattr_exit_error;
2290 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
2294 if (os_parse_xattr_streams) {
2296 * See if we can parse this stream, and ifso give it a try.
2298 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
2299 if (os_default_xattr_streams[cnt] == stream) {
2300 return (*os_parse_xattr_streams)(jcr, stream);
2305 * Issue a warning and discard the message. But pretend the restore was ok.
2307 Jmsg2(jcr, M_WARNING, 0,
2308 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
2309 jcr->last_fname, stream);
2310 return bxattr_exit_error;