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 * - FreeBSD (Extended Attributes)
36 * - Darwin (Extended Attributes)
37 * - Linux (Extended Attributes)
38 * - NetBSD (Extended Attributes)
39 * - Solaris (Extended Attributes and Extensible Attributes)
41 * Written by Marco van Wieringen, November MMVIII
50 #if !defined(HAVE_XATTR)
52 * Entry points when compiled without support for XATTRs or on an unsupported platform.
54 bsub_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
56 return bsub_exit_fatal;
59 bsub_exit_code parse_xattr_streams(JCR *jcr, int stream)
61 return bsub_exit_fatal;
65 * Send a XATTR stream to the SD.
67 static bsub_exit_code send_xattr_stream(JCR *jcr, int stream)
69 BSOCK *sd = jcr->store_bsock;
71 #ifdef FD_NO_SEND_TEST
78 if (jcr->xattr_data_len <= 0)
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 bsub_exit_fatal;
91 * Send the buffer to the storage deamon
93 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data);
95 sd->msg = jcr->xattr_data;
96 sd->msglen = jcr->xattr_data_len;
100 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
102 return bsub_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 bsub_exit_fatal;
112 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
117 * This is a supported OS, See what kind of interface we should use.
118 * Start with the generic interface used by most OS-es.
120 #if defined(HAVE_DARWIN_OS) || \
121 defined(HAVE_FREEBSD_OS) || \
122 defined(HAVE_LINUX_OS) || \
123 defined(HAVE_NETBSD_OS)
125 #ifdef HAVE_SYS_XATTR_H
126 #include <sys/xattr.h>
130 * All these os-es have 1 xattr stream.
132 #if defined(HAVE_DARWIN_OS)
133 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
134 #elif defined(HAVE_FREEBSD_OS)
135 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
136 #elif defined(HAVE_LINUX_OS)
137 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
138 #elif defined(HAVE_NETBSD_OS)
139 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
143 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
144 * listxattr, getxattr and setxattr with an extra options argument
145 * which mimics the l variants of the functions when we specify
146 * XATTR_NOFOLLOW as the options value.
148 #if defined(HAVE_DARWIN_OS)
149 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
150 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
151 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
154 * Fallback to the non l-functions when those are not available.
156 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
157 #define lgetxattr getxattr
159 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
160 #define lsetxattr setxattr
162 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
163 #define llistxattr listxattr
167 static void xattr_drop_internal_table(xattr_t *xattr_value_list)
169 xattr_t *current_xattr;
172 * Walk the list of xattrs and free allocated memory on traversing.
174 for (current_xattr = xattr_value_list;
175 current_xattr != (xattr_t *)NULL;
178 * See if we can shortcut.
180 if (current_xattr->magic != XATTR_MAGIC)
183 free(current_xattr->name);
185 if (current_xattr->value_length > 0)
186 free(current_xattr->value);
190 * Free the array of control structs.
192 free(xattr_value_list);
196 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
197 * which encodes one or more xattr_t structures.
199 * The Serialized stream consists of the following elements:
200 * magic - A magic string which makes it easy to detect any binary incompatabilites
201 * name_length - The length of the following xattr name
202 * name - The name of the extended attribute
203 * value_length - The length of the following xattr data
204 * value - The actual content of the extended attribute
206 * This is repeated 1 or more times.
209 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list)
211 xattr_t *current_xattr;
215 * Make sure the serialized stream fits in the poolmem buffer.
216 * We allocate some more to be sure the stream is gonna fit.
218 jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, expected_serialize_len + 10);
219 ser_begin(jcr->xattr_data, expected_serialize_len + 10);
222 * Walk the list of xattrs and serialize the data.
224 for (current_xattr = xattr_value_list; current_xattr != (xattr_t *)NULL; current_xattr++) {
226 * See if we can shortcut.
228 if (current_xattr->magic != XATTR_MAGIC)
231 ser_uint32(current_xattr->magic);
232 ser_uint32(current_xattr->name_length);
233 ser_bytes(current_xattr->name, current_xattr->name_length);
235 ser_uint32(current_xattr->value_length);
236 ser_bytes(current_xattr->value, current_xattr->value_length);
239 ser_end(jcr->xattr_data, expected_serialize_len + 10);
240 jcr->xattr_data_len = ser_length(jcr->xattr_data);
241 return jcr->xattr_data_len;
244 static bsub_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
247 int32_t xattr_list_len,
249 uint32_t expected_serialize_len = 0;
250 char *xattr_list, *bp;
251 xattr_t *xattr_value_list = NULL, *current_xattr;
255 * First get the length of the available list with extended attributes.
257 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
258 if (xattr_list_len < 0) {
261 return bsub_exit_nok;
263 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
264 jcr->last_fname, be.bstrerror());
265 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
266 jcr->last_fname, be.bstrerror());
267 return bsub_exit_nok;
269 } else if (xattr_list_len == 0) {
274 * Allocate room for the extented attribute list.
276 xattr_list = (char *)malloc(xattr_list_len + 1);
277 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
280 * Get the actual list of extended attributes names for a file.
282 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
283 if (xattr_list_len < 0) {
287 return bsub_exit_nok;
289 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
290 jcr->last_fname, be.bstrerror());
291 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
292 jcr->last_fname, be.bstrerror());
294 return bsub_exit_nok;
297 xattr_list[xattr_list_len] = '\0';
300 * Count the number of extended attributes on a file.
303 while ((bp - xattr_list) + 1 < xattr_list_len) {
304 #if defined(HAVE_LINUX_OS)
306 * On Linux you also get the acls in the extented attribute list.
307 * So we check if we are already backing up acls and if we do we
308 * don't store the extended attribute with the same info.
310 if ((ff_pkt->flags & FO_ACL) == 0 || strcmp(bp, "system.posix_acl_access"))
316 bp = strchr(bp, '\0') + 1;
320 retval = bsub_exit_ok;
325 * Allocate enough room to hold all extended attributes.
326 * After allocating the storage make sure its empty by zeroing it.
328 xattr_value_list = (xattr_t *)malloc(count * sizeof(xattr_t));
329 memset((caddr_t)xattr_value_list, 0, count * sizeof(xattr_t));
332 * Walk the list of extended attributes names and retrieve the data.
333 * We already count the bytes needed for serializing the stream later on.
335 current_xattr = xattr_value_list;
337 while ((bp - xattr_list) + 1 < xattr_list_len) {
338 #if defined(HAVE_LINUX_OS)
340 * On Linux you also get the acls in the extented attribute list.
341 * So we check if we are already backing up acls and if we do we
342 * don't store the extended attribute with the same info.
344 if (ff_pkt->flags & FO_ACL && !strcmp(bp, "system.posix_acl_access")) {
345 bp = strchr(bp, '\0') + 1;
351 * Each xattr valuepair starts with a magic so we can parse it easier.
353 current_xattr->magic = XATTR_MAGIC;
354 expected_serialize_len += sizeof(current_xattr->magic);
357 * Allocate space for storing the name.
359 current_xattr->name_length = strlen(bp);
360 current_xattr->name = (char *)malloc(current_xattr->name_length);
361 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
363 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
366 * First see how long the value is for the extended attribute.
368 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
369 if (xattr_value_len < 0) {
374 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
375 jcr->last_fname, be.bstrerror());
376 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
377 jcr->last_fname, be.bstrerror());
383 * Allocate space for storing the value.
385 current_xattr->value = (char *)malloc(xattr_value_len);
386 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
388 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
389 if (xattr_value_len < 0) {
394 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
395 jcr->last_fname, be.bstrerror());
396 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
397 jcr->last_fname, be.bstrerror());
403 * Store the actual length of the value.
405 current_xattr->value_length = xattr_value_len;
406 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
409 * Protect ourself against things getting out of hand.
411 if (expected_serialize_len >= MAX_XATTR_STREAM) {
412 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
413 jcr->last_fname, MAX_XATTR_STREAM);
421 bp = strchr(bp, '\0') + 1;
425 * Serialize the datastream.
427 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
428 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
430 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
435 xattr_drop_internal_table(xattr_value_list);
439 * Send the datastream to the SD.
441 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
444 if (xattr_value_list) {
445 xattr_drop_internal_table(xattr_value_list);
448 return bsub_exit_nok;
451 static bsub_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
454 xattr_t current_xattr;
455 bsub_exit_code retval = bsub_exit_nok;
459 * Parse the stream and perform the setxattr calls on the file.
461 * Start unserializing the data. We keep on looping while we have not
462 * unserialized all bytes in the stream.
464 unser_begin(jcr->xattr_data, jcr->xattr_data_len);
465 while (unser_length(jcr->xattr_data) < jcr->xattr_data_len) {
467 * First make sure the magic is present. This way we can easily catch corruption.
468 * Any missing MAGIC is fatal we do NOT try to continue.
470 unser_uint32(current_xattr.magic);
471 if (current_xattr.magic != XATTR_MAGIC) {
472 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
474 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
476 return bsub_exit_nok;
480 * Decode the valuepair. First decode the length of the name.
482 unser_uint32(current_xattr.name_length);
485 * Allocate room for the name and decode its content.
487 current_xattr.name = (char *)malloc(current_xattr.name_length + 1);
488 unser_bytes(current_xattr.name, current_xattr.name_length);
491 * The xattr_name needs to be null terminated for lsetxattr.
493 current_xattr.name[current_xattr.name_length] = '\0';
496 * Decode the value length.
498 unser_uint32(current_xattr.value_length);
501 * Allocate room for the value and decode its content.
503 current_xattr.value = (char *)malloc(current_xattr.value_length);
504 unser_bytes(current_xattr.value, current_xattr.value_length);
507 * Try to set the extended attribute on the file.
508 * If we fail to set this attribute we flag the error but its not fatal,
509 * we try to restore the other extended attributes too.
511 if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
512 current_xattr.value_length, 0) != 0) {
517 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
518 jcr->last_fname, be.bstrerror());
519 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
520 jcr->last_fname, be.bstrerror());
526 * Free the temporary buffers.
528 free(current_xattr.name);
529 free(current_xattr.value);
532 unser_end(jcr->xattr_data, jcr->xattr_data_len);
537 * For all these os-es setup the build and parse function pointer to the generic functions.
539 static bsub_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
540 static bsub_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
542 #elif defined(HAVE_SUN_OS)
544 * Solaris extended attributes were introduced in Solaris 9
547 * Solaris extensible attributes were introduced in OpenSolaris
548 * by PSARC 2007/315 Solaris extensible attributes are also
549 * sometimes called extended system attributes.
551 * man fsattr(5) on Solaris gives a wealth of info. The most
552 * important bits are:
554 * Attributes are logically supported as files within the file
555 * system. The file system is therefore augmented with an
556 * orthogonal name space of file attributes. Any file (includ-
557 * ing attribute files) can have an arbitrarily deep attribute
558 * tree associated with it. Attribute values are accessed by
559 * file descriptors obtained through a special attribute inter-
560 * face. This logical view of "attributes as files" allows the
561 * leveraging of existing file system interface functionality
562 * to support the construction, deletion, and manipulation of
565 * The special files "." and ".." retain their accustomed
566 * semantics within the attribute hierarchy. The "." attribute
567 * file refers to the current directory and the ".." attribute
568 * file refers to the parent directory. The unnamed directory
569 * at the head of each attribute tree is considered the "child"
570 * of the file it is associated with and the ".." file refers
571 * to the associated file. For any non-directory file with
572 * attributes, the ".." entry in the unnamed directory refers
573 * to a file that is not a directory.
575 * Conceptually, the attribute model is fully general. Extended
576 * attributes can be any type of file (doors, links, direc-
577 * tories, and so forth) and can even have their own attributes
578 * (fully recursive). As a result, the attributes associated
579 * with a file could be an arbitrarily deep directory hierarchy
580 * where each attribute could have an equally complex attribute
581 * tree associated with it. Not all implementations are able
582 * to, or want to, support the full model. Implementation are
583 * therefore permitted to reject operations that are not sup-
584 * ported. For example, the implementation for the UFS file
585 * system allows only regular files as attributes (for example,
586 * no sub-directories) and rejects attempts to place attributes
589 * The following list details the operations that are rejected
590 * in the current implementation:
592 * link Any attempt to create links between
593 * attribute and non-attribute space
594 * is rejected to prevent security-
595 * related or otherwise sensitive
596 * attributes from being exposed, and
597 * therefore manipulable, as regular
600 * rename Any attempt to rename between
601 * attribute and non-attribute space
602 * is rejected to prevent an already
603 * linked file from being renamed and
604 * thereby circumventing the link res-
607 * mkdir, symlink, mknod Any attempt to create a "non-
608 * regular" file in attribute space is
609 * rejected to reduce the functional-
610 * ity, and therefore exposure and
611 * risk, of the initial implementa-
614 * The entire available name space has been allocated to "gen-
615 * eral use" to bring the implementation in line with the NFSv4
616 * draft standard [NFSv4]. That standard defines "named attri-
617 * butes" (equivalent to Solaris Extended Attributes) with no
618 * naming restrictions. All Sun applications making use of
619 * opaque extended attributes will use the prefix "SUNW".
622 #ifdef HAVE_SYS_ATTR_H
623 #include <sys/attr.h>
630 #ifdef HAVE_SYS_NVPAIR_H
631 #include <sys/nvpair.h>
634 #ifdef HAVE_SYS_ACL_H
639 * Number of xattr streams this OS supports and an array with integers with the actual stream numbers.
641 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
642 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
644 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
645 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
648 * This is the count of xattrs saved on a certain file, it gets reset
649 * on each new file processed and is used to see if we need to send
650 * the hidden xattr dir data. We only send that data when we encounter
651 * an other xattr on the file.
653 static int nr_xattr_saved = 0;
654 static char toplevel_hidden_dir_xattr_data[MAXSTRING];
655 static int toplevel_hidden_dir_xattr_data_len;
658 * This code creates a temporary cache with entries for each xattr which has
659 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
661 static alist *xattr_link_cache = NULL;
663 static struct xattr_link_cache_entry *find_xattr_link_cache_entry(ino_t inum)
665 xattr_link_cache_entry_t *ptr;
667 foreach_alist(ptr, xattr_link_cache) {
668 if (ptr && ptr->inum == inum) {
675 static void add_xattr_link_cache_entry(ino_t inum, char *target)
677 xattr_link_cache_entry_t *ptr;
679 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(struct xattr_link_cache_entry));
680 memset((caddr_t)ptr, 0, sizeof(struct xattr_link_cache_entry));
682 bstrncpy(ptr->target, target, sizeof(ptr->target));
683 xattr_link_cache->append(ptr);
686 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
688 * This function returns true if a non default extended system attribute
689 * list is associated with fd and returns false when an error has occured
690 * or when only extended system attributes other than archive,
691 * av_modified or crtime are set.
693 * The function returns true for the following cases:
695 * - any extended system attribute other than the default attributes
696 * ('archive', 'av_modified' and 'crtime') is set
697 * - nvlist has NULL name string
698 * - nvpair has data type of 'nvlist'
699 * - default data type.
701 static bool solaris_has_non_transient_extensible_attributes(int fd)
711 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
716 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
717 name = nvpair_name(pair);
720 fattr = name_to_attr(name);
726 type = nvpair_type(pair);
728 case DATA_TYPE_BOOLEAN_VALUE:
729 if (nvpair_value_boolean_value(pair, &value) != 0) {
732 if (value && fattr != F_ARCHIVE &&
733 fattr != F_AV_MODIFIED) {
738 case DATA_TYPE_UINT64_ARRAY:
739 if (fattr != F_CRTIME) {
744 case DATA_TYPE_NVLIST:
752 if (response != NULL) {
753 nvlist_free(response);
757 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
759 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
761 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
762 * There is no need to store those acls as we already store the stat bits too.
764 static bool acl_is_trivial(int count, aclent_t *entries)
769 for (n = 0; n < count; n++) {
771 if (!(ace->a_type == USER_OBJ ||
772 ace->a_type == GROUP_OBJ ||
773 ace->a_type == OTHER_OBJ ||
774 ace->a_type == CLASS_OBJ))
779 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
781 static bsub_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
784 #ifdef HAVE_EXTENDED_ACL
790 * See if this attribute has an ACL
792 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
793 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
795 * See if there is a non trivial acl on the file.
797 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
798 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
801 return bsub_exit_nok;
803 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
804 attrname, jcr->last_fname, be.bstrerror());
805 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
806 attrname, jcr->last_fname, be.bstrerror());
807 return bsub_exit_nok;
812 #if defined(ACL_SID_FMT)
814 * New format flag added in newer Solaris versions.
816 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
818 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
819 #endif /* ACL_SID_FMT */
821 *acl_text = acl_totext(aclp, flags);
830 #else /* HAVE_EXTENDED_ACL */
832 aclent_t *acls = NULL;
836 * See if this attribute has an ACL
839 n = facl(fd, GETACLCNT, 0, NULL);
841 n = acl(attrname, GETACLCNT, 0, NULL);
844 if (n >= MIN_ACL_ENTRIES) {
845 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
846 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
847 acl(attrname, GETACL, n, acls) != n) {
851 return bsub_exit_nok;
853 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
854 attrname, jcr->last_fname, be.bstrerror());
855 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
856 attrname, jcr->last_fname, be.bstrerror());
858 return bsub_exit_nok;
863 * See if there is a non trivial acl on the file.
865 if (!acl_is_trivial(n, acls)) {
866 if ((*acl_text = acltotext(acls, n)) == NULL) {
867 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
868 attrname, jcr->last_fname, be.bstrerror());
869 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
870 attrname, jcr->last_fname, be.bstrerror());
872 return bsub_exit_nok;
883 #endif /* HAVE_EXTENDED_ACL */
887 #endif /* HAVE_ACL */
891 * Forward declaration for recursive function call.
893 static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
896 * Save an extended or extensible attribute.
897 * This is stored as an opaque stream of bytes with the following encoding:
899 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
901 * or for a hardlinked or symlinked attribute
903 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
905 * xattr_name can be a subpath relative to the file the xattr is on.
906 * stat_buffer is the string representation of the stat struct.
907 * acl_string is an acl text when a non trivial acl is set on the xattr.
908 * actual_xattr_data is the content of the xattr file.
910 static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
911 const char *attrname, bool toplevel_hidden_dir, int stream)
916 struct xattr_link_cache_entry *xlce;
917 char target_attrname[PATH_MAX];
918 char link_source[PATH_MAX];
919 char *acl_text = NULL;
920 char attribs[MAXSTRING];
922 bsub_exit_code retval = bsub_exit_nok;
925 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
928 * Get the stats of the extended or extensible attribute.
930 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
935 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
936 target_attrname, jcr->last_fname, be.bstrerror());
937 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
938 target_attrname, jcr->last_fname, be.bstrerror());
944 * Based on the filetype perform the correct action. We support most filetypes here, more
945 * then the actual implementation on Solaris supports so some code may never get executed
946 * due to limitations in the implementation.
948 switch (st.st_mode & S_IFMT) {
953 * Get any acl on the xattr.
955 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok)
959 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
960 * Encode the stat struct into an ASCII representation.
962 encode_stat(attribs, &st, 0, stream);
963 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
964 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
969 * Get any acl on the xattr.
971 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok)
975 * See if this is the toplevel_hidden_dir being saved.
977 if (toplevel_hidden_dir) {
979 * Save the data for later storage when we encounter a real xattr.
980 * Encode the stat struct into an ASCII representation and jump out of the function.
982 encode_stat(attribs, &st, 0, stream);
983 toplevel_hidden_dir_xattr_data_len = bsnprintf(toplevel_hidden_dir_xattr_data,
984 sizeof(toplevel_hidden_dir_xattr_data),
986 target_attrname, 0, attribs, 0,
987 (acl_text) ? acl_text : "", 0);
991 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
992 * Encode the stat struct into an ASCII representation.
994 encode_stat(attribs, &st, 0, stream);
995 cnt = bsnprintf(buffer, sizeof(buffer),
997 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1002 * If this is a hardlinked file check the inode cache for a hit.
1004 if (st.st_nlink > 1) {
1006 * See if the cache already knows this inode number.
1008 if ((xlce = find_xattr_link_cache_entry(st.st_ino)) != NULL) {
1010 * Generate a xattr encoding with the reference to the target in there.
1012 encode_stat(attribs, &st, st.st_ino, stream);
1013 cnt = bsnprintf(buffer, sizeof(buffer),
1015 target_attrname, 0, attribs, 0, xlce->target, 0);
1016 pm_memcpy(jcr->xattr_data, buffer, cnt);
1017 jcr->xattr_data_len = cnt;
1018 retval = send_xattr_stream(jcr, stream);
1021 * For a hard linked file we are ready now, no need to recursively save the attributes.
1027 * Store this hard linked file in the cache.
1028 * Store the name relative to the top level xattr space.
1030 add_xattr_link_cache_entry(st.st_ino, target_attrname + 1);
1034 * Get any acl on the xattr.
1036 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok) {
1041 * Encode the stat struct into an ASCII representation.
1043 encode_stat(attribs, &st, 0, stream);
1044 cnt = bsnprintf(buffer, sizeof(buffer),
1046 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1049 * Open the extended or extensible attribute file.
1051 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1056 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1057 target_attrname, jcr->last_fname, be.bstrerror());
1058 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1059 target_attrname, jcr->last_fname, be.bstrerror());
1067 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1068 * Encode the stat struct into an ASCII representation.
1070 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1075 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1076 target_attrname, jcr->last_fname, be.bstrerror());
1077 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1078 target_attrname, jcr->last_fname, be.bstrerror());
1084 * Generate a xattr encoding with the reference to the target in there.
1086 encode_stat(attribs, &st, st.st_ino, stream);
1087 cnt = bsnprintf(buffer, sizeof(buffer),
1089 target_attrname, 0, attribs, 0, link_source, 0);
1090 pm_memcpy(jcr->xattr_data, buffer, cnt);
1091 jcr->xattr_data_len = cnt;
1092 retval = send_xattr_stream(jcr, stream);
1095 * For a soft linked file we are ready now, no need to recursively save the attributes.
1104 * See if this is the first real xattr being saved. If it is save the toplevel_hidden_dir attributes first.
1106 if (nr_xattr_saved == 0) {
1107 pm_memcpy(jcr->xattr_data, toplevel_hidden_dir_xattr_data, toplevel_hidden_dir_xattr_data_len);
1108 jcr->xattr_data_len = toplevel_hidden_dir_xattr_data_len;
1109 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1112 pm_memcpy(jcr->xattr_data, buffer, cnt);
1113 jcr->xattr_data_len = cnt;
1116 * Only dump the content of regular files.
1118 switch (st.st_mode & S_IFMT) {
1120 if (st.st_size > 0) {
1122 * Protect ourself against things getting out of hand.
1124 if (st.st_size >= MAX_XATTR_STREAM) {
1125 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1126 jcr->last_fname, MAX_XATTR_STREAM);
1130 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1131 jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, jcr->xattr_data_len + cnt);
1132 memcpy(jcr->xattr_data + jcr->xattr_data_len, buffer, cnt);
1133 jcr->xattr_data_len += cnt;
1137 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
1138 target_attrname, jcr->last_fname);
1139 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1140 target_attrname, jcr->last_fname);
1151 retval = send_xattr_stream(jcr, stream);
1156 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1157 * available on this extended attribute.
1160 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1163 * The recursive call could change our working dir so change back to the wanted workdir.
1165 if (fchdir(fd) < 0) {
1170 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1171 jcr->last_fname, be.bstrerror());
1172 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1173 jcr->last_fname, fd, be.bstrerror());
1189 static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1192 int fd, filefd = -1, attrdirfd = -1;
1195 char current_xattr_namespace[PATH_MAX];
1196 bsub_exit_code retval = bsub_exit_nok;
1200 * Determine what argument to use. Use attr_parent when set
1201 * (recursive call) or jcr->last_fname for first call. Also save
1202 * the current depth of the xattr_space we are in.
1206 if (xattr_namespace) {
1207 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1208 xattr_namespace, attr_parent);
1210 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1213 name = jcr->last_fname;
1214 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1218 * Open the file on which to save the xattrs read-only.
1220 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1225 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1226 jcr->last_fname, be.bstrerror());
1227 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1228 jcr->last_fname, be.bstrerror());
1234 * Open the xattr naming space.
1236 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1240 * Gentile way of the system saying this type of xattr layering is not supported.
1241 * Which is not problem we just forget about this this xattr.
1242 * But as this is not an error we return a positive return value.
1244 retval = bsub_exit_ok;
1249 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1250 name, jcr->last_fname, be.bstrerror());
1251 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1252 name, jcr->last_fname, be.bstrerror());
1258 * We need to change into the attribute directory to determine if each of the
1259 * attributes should be saved.
1261 if (fchdir(attrdirfd) < 0) {
1262 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1263 jcr->last_fname, be.bstrerror());
1264 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1265 jcr->last_fname, attrdirfd, be.bstrerror());
1270 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1271 * else because the readdir returns "." entry after the extensible attr entry.
1272 * And as we want this entry before anything else we better just save its data.
1275 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1276 true, STREAM_XATTR_SOLARIS);
1278 if ((fd = dup(attrdirfd)) == -1 ||
1279 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1280 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1281 jcr->last_fname, be.bstrerror());
1282 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1283 jcr->last_fname, fd, be.bstrerror());
1289 * Walk the namespace.
1291 while (dp = readdir(dirp)) {
1293 * Skip only the toplevel . dir.
1295 if (!attr_parent && !strcmp(dp->d_name, "."))
1299 * Skip all .. directories
1301 if (!strcmp(dp->d_name, ".."))
1304 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1305 current_xattr_namespace, dp->d_name, jcr->last_fname);
1307 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1309 * We are not interested in read-only extensible attributes.
1311 if (!strcmp(dp->d_name, VIEW_READONLY)) {
1312 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1313 current_xattr_namespace, dp->d_name, jcr->last_fname);
1319 * We are only interested in read-write extensible attributes
1320 * when they contain non-transient values.
1322 if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1324 * Determine if there are non-transient system attributes at the toplevel.
1325 * We need to provide a fd to the open file.
1327 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1328 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1329 current_xattr_namespace, dp->d_name, jcr->last_fname);
1336 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1337 false, STREAM_XATTR_SOLARIS_SYS);
1340 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1345 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1346 false, STREAM_XATTR_SOLARIS);
1350 retval = bsub_exit_ok;
1353 if (attrdirfd != -1)
1361 static bsub_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1363 #ifdef HAVE_EXTENDED_ACL
1368 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1369 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
1371 return bsub_exit_nok;
1374 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1375 acl_set(attrname, aclp) != 0) {
1376 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1377 attrname, jcr->last_fname, be.bstrerror());
1378 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1379 attrname, jcr->last_fname, be.bstrerror());
1380 return bsub_exit_nok;
1386 return bsub_exit_ok;
1388 #else /* HAVE_EXTENDED_ACL */
1390 aclent_t *acls = NULL;
1393 acls = aclfromtext(acl_text, &n);
1395 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1396 acl(attrname, SETACL, n, acls) != 0) {
1397 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1398 attrname, jcr->last_fname, be.bstrerror());
1399 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1400 attrname, jcr->last_fname, be.bstrerror());
1401 return bsub_exit_nok;
1408 return bsub_exit_ok;
1410 #endif /* HAVE_EXTENDED_ACL */
1413 #endif /* HAVE_ACL */
1415 static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1417 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1418 int used_bytes, total_bytes, cnt;
1419 char *bp, *target_attrname, *attribs;
1420 char *linked_target = NULL;
1421 char *acl_text = NULL;
1425 struct timeval times[2];
1426 bsub_exit_code retval = bsub_exit_nok;
1430 * Parse the xattr stream. First the part that is the same for all xattrs.
1433 total_bytes = jcr->xattr_data_len;
1436 * The name of the target xattr has a leading / we are not interested
1437 * in that so skip it when decoding the string. We always start a the /
1438 * of the xattr space anyway.
1440 target_attrname = jcr->xattr_data + 1;
1441 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1442 (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1448 * Open the file on which to restore the xattrs read-only.
1450 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1451 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1452 jcr->last_fname, be.bstrerror());
1453 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1454 jcr->last_fname, be.bstrerror());
1459 * Open the xattr naming space and make it the current working dir.
1461 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1462 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1463 jcr->last_fname, be.bstrerror());
1464 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1465 jcr->last_fname, be.bstrerror());
1469 if (fchdir(attrdirfd) < 0) {
1470 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1471 jcr->last_fname, be.bstrerror());
1472 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1473 jcr->last_fname, attrdirfd, be.bstrerror());
1478 * Try to open the correct xattr subdir based on the target_attrname given.
1479 * e.g. check if its a subdir attrname. Each / in the string makes us go
1482 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1485 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1486 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1487 target_attrname, jcr->last_fname, be.bstrerror());
1488 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1489 target_attrname, jcr->last_fname, be.bstrerror());
1497 * Open the xattr naming space.
1499 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1500 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1501 target_attrname, jcr->last_fname, be.bstrerror());
1502 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1503 target_attrname, jcr->last_fname, be.bstrerror());
1511 * Make the xattr space our current workingdir.
1513 if (fchdir(attrdirfd) < 0) {
1514 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1515 target_attrname, jcr->last_fname, be.bstrerror());
1516 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1517 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1521 target_attrname = ++bp;
1525 * Decode the attributes from the stream.
1527 decode_stat(attribs, &st, &inum);
1530 * Decode the next field (acl_text).
1532 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1533 (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1539 * Based on the filetype perform the correct action. We support most filetypes here, more
1540 * then the actual implementation on Solaris supports so some code may never get executed
1541 * due to limitations in the implementation.
1543 switch (st.st_mode & S_IFMT) {
1546 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1548 unlinkat(attrdirfd, target_attrname, 0);
1549 if (mkfifo(target_attrname, st.st_mode) < 0) {
1550 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1551 target_attrname, jcr->last_fname, be.bstrerror());
1552 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1553 target_attrname, jcr->last_fname, be.bstrerror());
1560 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1562 unlinkat(attrdirfd, target_attrname, 0);
1563 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1564 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1565 target_attrname, jcr->last_fname, be.bstrerror());
1566 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1567 target_attrname, jcr->last_fname, be.bstrerror());
1573 * If its not the hidden_dir create the entry.
1574 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1576 if (strcmp(target_attrname, ".")) {
1577 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1578 if (mkdir(target_attrname, st.st_mode) < 0) {
1579 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1580 target_attrname, jcr->last_fname, be.bstrerror());
1581 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1582 target_attrname, jcr->last_fname, be.bstrerror());
1589 * See if this is a hard linked file. e.g. inum != 0
1594 unlinkat(attrdirfd, target_attrname, 0);
1595 if (link(linked_target, target_attrname) < 0) {
1596 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1597 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1598 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1599 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1604 * Successfully restored xattr.
1606 retval = bsub_exit_ok;
1609 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1610 (used_bytes = (bp - jcr->xattr_data)) >= total_bytes) {
1614 if (used_bytes < (total_bytes - 1))
1618 * Restore the actual xattr.
1620 if (!is_extensible) {
1621 unlinkat(attrdirfd, target_attrname, 0);
1624 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1625 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1626 target_attrname, jcr->last_fname, be.bstrerror());
1627 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1628 target_attrname, jcr->last_fname, be.bstrerror());
1634 * Restore the actual data.
1636 if (st.st_size > 0) {
1637 used_bytes = (data - jcr->xattr_data);
1638 cnt = total_bytes - used_bytes;
1641 * Do a sanity check, the st.st_size should be the same as the number of bytes
1642 * we have available as data of the stream.
1644 if (cnt != st.st_size) {
1645 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
1646 target_attrname, jcr->last_fname);
1647 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1648 target_attrname, jcr->last_fname);
1653 cnt = write(attrfd, data, cnt);
1655 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
1656 target_attrname, jcr->last_fname, be.bstrerror());
1657 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
1658 target_attrname, jcr->last_fname, be.bstrerror());
1664 cnt = total_bytes - used_bytes;
1670 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1674 if (symlink(linked_target, target_attrname) < 0) {
1675 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
1676 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1677 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
1678 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1683 * Successfully restored xattr.
1685 retval = bsub_exit_ok;
1692 * Restore owner and acl for non extensible attributes.
1694 if (!is_extensible) {
1695 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
1699 * Gentile way of the system saying this type of xattr layering is not supported.
1700 * But as this is not an error we return a positive return value.
1702 retval = bsub_exit_ok;
1705 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1706 target_attrname, jcr->last_fname, be.bstrerror());
1707 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1708 target_attrname, jcr->last_fname, be.bstrerror());
1715 if (acl_text && *acl_text)
1716 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bsub_exit_ok)
1718 #endif /* HAVE_ACL */
1721 * For a non extensible attribute restore access and modification time on the xattr.
1723 if (!is_extensible) {
1724 times[0].tv_sec = st.st_atime;
1725 times[0].tv_usec = 0;
1726 times[1].tv_sec = st.st_mtime;
1727 times[1].tv_usec = 0;
1729 if (futimesat(attrdirfd, target_attrname, times) < 0) {
1730 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
1731 target_attrname, jcr->last_fname, be.bstrerror());
1732 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
1733 target_attrname, jcr->last_fname, be.bstrerror());
1739 * Successfully restored xattr.
1741 retval = bsub_exit_ok;
1745 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
1747 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
1754 if (attrdirfd != -1) {
1763 static bsub_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1766 bsub_exit_code retval = bsub_exit_ok;
1769 * First see if extended attributes or extensible attributes are present.
1770 * If not just pretend things went ok.
1772 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1776 * As we change the cwd in the save function save the current cwd
1777 * for restore after return from the solaris_save_xattrs function.
1779 xattr_link_cache = New(alist(10, not_owned_by_alist));
1780 getcwd(cwd, sizeof(cwd));
1781 retval = solaris_save_xattrs(jcr, NULL, NULL);
1783 delete xattr_link_cache;
1784 xattr_link_cache = NULL;
1789 static bsub_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
1792 bool is_extensible = false;
1793 bsub_exit_code retval;
1796 * First make sure we can restore xattr on the filesystem.
1799 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1800 case STREAM_XATTR_SOLARIS_SYS:
1801 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1802 Qmsg1(jcr, M_WARNING, 0,
1803 _("Failed to restore extensible attributes on file \"%s\"\n"),
1805 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1807 return bsub_exit_nok;
1810 is_extensible = true;
1813 case STREAM_XATTR_SOLARIS:
1814 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1815 Qmsg1(jcr, M_WARNING, 0,
1816 _("Failed to restore extended attributes on file \"%s\"\n"),
1818 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1820 return bsub_exit_nok;
1824 return bsub_exit_nok;
1828 * As we change the cwd in the restore function save the current cwd
1829 * for restore after return from the solaris_restore_xattrs function.
1831 getcwd(cwd, sizeof(cwd));
1832 retval = solaris_restore_xattrs(jcr, is_extensible);
1839 * Function pointers to the build and parse function to use for these xattrs.
1841 static bsub_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
1842 static bsub_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
1844 #endif /* defined(HAVE_SUN_OS) */
1846 bsub_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1848 if (os_build_xattr_streams) {
1849 return (*os_build_xattr_streams)(jcr, ff_pkt);
1851 return bsub_exit_nok;
1854 bsub_exit_code parse_xattr_streams(JCR *jcr, int stream)
1858 if (os_parse_xattr_streams) {
1860 * See if we can parse this stream, and ifso give it a try.
1862 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
1863 if (os_default_xattr_streams[cnt] == stream) {
1864 return (*os_parse_xattr_streams)(jcr, stream);
1869 * Issue a warning and discard the message. But pretend the restore was ok.
1871 Jmsg2(jcr, M_WARNING, 0,
1872 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1873 jcr->last_fname, stream);
1874 return bsub_exit_nok;