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, int default_stream)
247 int32_t xattr_list_len,
249 uint32_t expected_serialize_len = 0;
250 char *xattr_list, *bp;
251 xattr_t *xattr_value_list, *current_xattr;
254 * First get the length of the available list with extended attributes.
256 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
257 if (xattr_list_len < 0) {
260 return bsub_exit_nok;
263 Jmsg2(jcr, M_ERROR, 0, _("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;
290 Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
291 jcr->last_fname, be.bstrerror());
292 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
293 jcr->last_fname, be.bstrerror());
295 return bsub_exit_nok;
298 xattr_list[xattr_list_len] = '\0';
301 * Count the number of extended attributes on a file.
304 while ((bp - xattr_list) + 1 < xattr_list_len) {
305 #if defined(HAVE_LINUX_OS)
307 * On Linux you also get the acls in the extented attribute list.
308 * So we check if we are already backing up acls and if we do we
309 * don't store the extended attribute with the same info.
311 if ((ff_pkt->flags & FO_ACL) == 0 || strcmp(bp, "system.posix_acl_access"))
317 bp = strchr(bp, '\0') + 1;
326 * Allocate enough room to hold all extended attributes.
327 * After allocating the storage make sure its empty by zeroing it.
329 xattr_value_list = (xattr_t *)malloc(count * sizeof(xattr_t));
330 memset((caddr_t)xattr_value_list, 0, count * sizeof(xattr_t));
333 * Walk the list of extended attributes names and retrieve the data.
334 * We already count the bytes needed for serializing the stream later on.
336 current_xattr = xattr_value_list;
338 while ((bp - xattr_list) + 1 < xattr_list_len) {
339 #if defined(HAVE_LINUX_OS)
340 if (ff_pkt->flags & FO_ACL && !strcmp(bp, "system.posix_acl_access")) {
341 bp = strchr(bp, '\0') + 1;
347 * Each xattr valuepair starts with a magic so we can parse it easier.
349 current_xattr->magic = XATTR_MAGIC;
350 expected_serialize_len += sizeof(current_xattr->magic);
353 * Allocate space for storing the name.
355 current_xattr->name_length = strlen(bp);
356 current_xattr->name = (char *)malloc(current_xattr->name_length);
357 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
359 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
362 * First see how long the value is for the extended attribute.
364 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
365 if (xattr_value_len < 0) {
371 Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
372 jcr->last_fname, be.bstrerror());
373 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
374 jcr->last_fname, be.bstrerror());
380 * Allocate space for storing the value.
382 current_xattr->value = (char *)malloc(xattr_value_len);
383 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
385 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
386 if (xattr_value_len < 0) {
392 Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
393 jcr->last_fname, be.bstrerror());
394 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
395 jcr->last_fname, be.bstrerror());
401 * Store the actual length of the value.
403 current_xattr->value_length = xattr_value_len;
404 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
407 * Protect ourself against things getting out of hand.
409 if (expected_serialize_len >= MAX_XATTR_STREAM) {
410 Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
411 jcr->last_fname, MAX_XATTR_STREAM);
419 bp = strchr(bp, '\0') + 1;
423 * Serialize the datastream.
425 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
426 Jmsg1(jcr, M_ERROR, 0, _("Failed to serialize extended attributes on file \"%s\"\n"),
428 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
433 xattr_drop_internal_table(xattr_value_list);
437 * Send the datastream to the SD.
439 return send_xattr_stream(jcr, default_stream);
442 xattr_drop_internal_table(xattr_value_list);
444 return bsub_exit_nok;
447 static bsub_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
450 xattr_t current_xattr;
451 bsub_exit_code retval = bsub_exit_nok;
454 * Parse the stream and perform the setxattr calls on the file.
456 * Start unserializing the data. We keep on looping while we have not
457 * unserialized all bytes in the stream.
459 unser_begin(jcr->xattr_data, jcr->xattr_data_len);
460 while (unser_length(jcr->xattr_data) < jcr->xattr_data_len) {
462 * First make sure the magic is present. This way we can easily catch corruption.
463 * Any missing MAGIC is fatal we do NOT try to continue.
465 unser_uint32(current_xattr.magic);
466 if (current_xattr.magic != XATTR_MAGIC) {
467 Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
469 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
471 return bsub_exit_nok;
475 * Decode the valuepair. First decode the length of the name.
477 unser_uint32(current_xattr.name_length);
480 * Allocate room for the name and decode its content.
482 current_xattr.name = (char *)malloc(current_xattr.name_length + 1);
483 unser_bytes(current_xattr.name, current_xattr.name_length);
486 * The xattr_name needs to be null terminated for lsetxattr.
488 current_xattr.name[current_xattr.name_length] = '\0';
491 * Decode the value length.
493 unser_uint32(current_xattr.value_length);
496 * Allocate room for the value and decode its content.
498 current_xattr.value = (char *)malloc(current_xattr.value_length);
499 unser_bytes(current_xattr.value, current_xattr.value_length);
502 * Try to set the extended attribute on the file.
503 * If we fail to set this attribute we flag the error but its not fatal,
504 * we try to restore the other extended attributes too.
506 if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
511 current_xattr.value_length, 0) != 0) {
513 Jmsg2(jcr, M_ERROR, 0, _("lsetxattr error on file \"%s\": ERR=%s\n"),
514 jcr->last_fname, be.bstrerror());
515 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
516 jcr->last_fname, be.bstrerror());
522 * Free the temporary buffers.
524 free(current_xattr.name);
525 free(current_xattr.value);
528 unser_end(jcr->xattr_data, jcr->xattr_data_len);
533 * For all these os-es setup the build and parse function pointer to the generic functions.
535 static bsub_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt, int default_stream) = generic_xattr_build_streams;
536 static bsub_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
538 #elif defined(HAVE_SUN_OS)
540 * Solaris extended attributes were introduced in Solaris 9
543 * Solaris extensible attributes were introduced in OpenSolaris
544 * by PSARC 2007/315 Solaris extensible attributes are also
545 * sometimes called extended system attributes.
547 * man fsattr(5) on Solaris gives a wealth of info. The most
548 * important bits are:
550 * Attributes are logically supported as files within the file
551 * system. The file system is therefore augmented with an
552 * orthogonal name space of file attributes. Any file (includ-
553 * ing attribute files) can have an arbitrarily deep attribute
554 * tree associated with it. Attribute values are accessed by
555 * file descriptors obtained through a special attribute inter-
556 * face. This logical view of "attributes as files" allows the
557 * leveraging of existing file system interface functionality
558 * to support the construction, deletion, and manipulation of
561 * The special files "." and ".." retain their accustomed
562 * semantics within the attribute hierarchy. The "." attribute
563 * file refers to the current directory and the ".." attribute
564 * file refers to the parent directory. The unnamed directory
565 * at the head of each attribute tree is considered the "child"
566 * of the file it is associated with and the ".." file refers
567 * to the associated file. For any non-directory file with
568 * attributes, the ".." entry in the unnamed directory refers
569 * to a file that is not a directory.
571 * Conceptually, the attribute model is fully general. Extended
572 * attributes can be any type of file (doors, links, direc-
573 * tories, and so forth) and can even have their own attributes
574 * (fully recursive). As a result, the attributes associated
575 * with a file could be an arbitrarily deep directory hierarchy
576 * where each attribute could have an equally complex attribute
577 * tree associated with it. Not all implementations are able
578 * to, or want to, support the full model. Implementation are
579 * therefore permitted to reject operations that are not sup-
580 * ported. For example, the implementation for the UFS file
581 * system allows only regular files as attributes (for example,
582 * no sub-directories) and rejects attempts to place attributes
585 * The following list details the operations that are rejected
586 * in the current implementation:
588 * link Any attempt to create links between
589 * attribute and non-attribute space
590 * is rejected to prevent security-
591 * related or otherwise sensitive
592 * attributes from being exposed, and
593 * therefore manipulable, as regular
596 * rename Any attempt to rename between
597 * attribute and non-attribute space
598 * is rejected to prevent an already
599 * linked file from being renamed and
600 * thereby circumventing the link res-
603 * mkdir, symlink, mknod Any attempt to create a "non-
604 * regular" file in attribute space is
605 * rejected to reduce the functional-
606 * ity, and therefore exposure and
607 * risk, of the initial implementa-
610 * The entire available name space has been allocated to "gen-
611 * eral use" to bring the implementation in line with the NFSv4
612 * draft standard [NFSv4]. That standard defines "named attri-
613 * butes" (equivalent to Solaris Extended Attributes) with no
614 * naming restrictions. All Sun applications making use of
615 * opaque extended attributes will use the prefix "SUNW".
618 #ifdef HAVE_SYS_ATTR_H
619 #include <sys/attr.h>
626 #ifdef HAVE_SYS_NVPAIR_H
627 #include <sys/nvpair.h>
630 #ifdef HAVE_SYS_ACL_H
635 * Number of xattr streams this OS supports and an array with integers with the actual stream numbers.
637 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
638 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
640 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
641 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
644 * This is the count of xattrs saved on a certain file, it gets reset
645 * on each new file processed and is used to see if we need to send
646 * the hidden xattr dir data. We only send that data when we encounter
647 * an other xattr on the file.
649 static int nr_xattr_saved = 0;
650 static char toplevel_hidden_dir_xattr_data[MAXSTRING];
651 static int toplevel_hidden_dir_xattr_data_len;
654 * This code creates a temporary cache with entries for each xattr which has
655 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
657 static alist *xattr_link_cache = NULL;
659 static struct xattr_link_cache_entry *find_xattr_link_cache_entry(ino_t inum)
661 xattr_link_cache_entry_t *ptr;
663 foreach_alist(ptr, xattr_link_cache) {
664 if (ptr && ptr->inum == inum) {
671 static void add_xattr_link_cache_entry(ino_t inum, char *target)
673 xattr_link_cache_entry_t *ptr;
675 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(struct xattr_link_cache_entry));
676 memset((caddr_t)ptr, 0, sizeof(struct xattr_link_cache_entry));
678 strncpy(ptr->target, target, sizeof(ptr->target));
679 xattr_link_cache->append(ptr);
682 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
684 * This function returns true if a non default extended system attribute
685 * list is associated with fd and returns false when an error has occured
686 * or when only extended system attributes other than archive,
687 * av_modified or crtime are set.
689 * The function returns true for the following cases:
691 * - any extended system attribute other than the default attributes
692 * ('archive', 'av_modified' and 'crtime') is set
693 * - nvlist has NULL name string
694 * - nvpair has data type of 'nvlist'
695 * - default data type.
697 static bool solaris_has_non_transient_extensible_attributes(int fd)
707 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
712 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
713 name = nvpair_name(pair);
716 fattr = name_to_attr(name);
722 type = nvpair_type(pair);
724 case DATA_TYPE_BOOLEAN_VALUE:
725 if (nvpair_value_boolean_value(pair, &value) != 0) {
728 if (value && fattr != F_ARCHIVE &&
729 fattr != F_AV_MODIFIED) {
734 case DATA_TYPE_UINT64_ARRAY:
735 if (fattr != F_CRTIME) {
740 case DATA_TYPE_NVLIST:
748 if (response != NULL) {
749 nvlist_free(response);
753 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
755 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
757 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
758 * There is no need to store those acls as we already store the stat bits too.
760 static bool acl_is_trivial(int count, aclent_t *entries)
765 for (n = 0; n < count; n++) {
767 if (!(ace->a_type == USER_OBJ ||
768 ace->a_type == GROUP_OBJ ||
769 ace->a_type == OTHER_OBJ ||
770 ace->a_type == CLASS_OBJ))
775 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
777 static bsub_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
780 #ifdef HAVE_EXTENDED_ACL
785 * See if this attribute has an ACL
787 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
788 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
790 * See if there is a non trivial acl on the file.
792 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
793 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
796 return bsub_exit_nok;
799 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
800 attrname, jcr->last_fname, be.bstrerror());
801 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
802 attrname, jcr->last_fname, be.bstrerror());
803 return bsub_exit_nok;
808 #if defined(ACL_SID_FMT)
810 * New format flag added in newer Solaris versions.
812 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
814 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
815 #endif /* ACL_SID_FMT */
817 *acl_text = acl_totext(aclp, flags);
826 #else /* HAVE_EXTENDED_ACL */
828 aclent_t *acls = NULL;
831 * See if this attribute has an ACL
834 n = facl(fd, GETACLCNT, 0, NULL);
836 n = acl(attrname, GETACLCNT, 0, NULL);
839 if (n >= MIN_ACL_ENTRIES) {
840 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
841 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
842 acl(attrname, GETACL, n, acls) != n) {
846 return bsub_exit_nok;
849 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
850 attrname, jcr->last_fname, be.bstrerror());
851 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
852 attrname, jcr->last_fname, be.bstrerror());
854 return bsub_exit_nok;
859 * See if there is a non trivial acl on the file.
861 if (!acl_is_trivial(n, acls)) {
862 if ((*acl_text = acltotext(acls, n)) == NULL) {
864 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
865 attrname, jcr->last_fname, be.bstrerror());
866 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
867 attrname, jcr->last_fname, be.bstrerror());
869 return bsub_exit_nok;
880 #endif /* HAVE_EXTENDED_ACL */
884 #endif /* HAVE_ACL */
888 * Forward declaration for recursive function call.
890 static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
893 * Save an extended or extensible attribute.
894 * This is stored as an opaque stream of bytes with the following encoding:
896 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
898 * or for a hardlinked or symlinked attribute
900 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
902 * xattr_name can be a subpath relative to the file the xattr is on.
903 * stat_buffer is the string representation of the stat struct.
904 * acl_string is an acl text when a non trivial acl is set on the xattr.
905 * actual_xattr_data is the content of the xattr file.
907 static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
908 const char *attrname, bool toplevel_hidden_dir, int stream)
913 struct xattr_link_cache_entry *xlce;
914 char target_attrname[PATH_MAX];
915 char link_source[PATH_MAX];
916 char *acl_text = NULL;
917 char attribs[MAXSTRING];
919 bsub_exit_code retval = bsub_exit_nok;
921 snprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
924 * Get the stats of the extended or extensible attribute.
926 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
932 Jmsg3(jcr, M_ERROR, 0, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
933 target_attrname, jcr->last_fname, be.bstrerror());
934 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
935 target_attrname, jcr->last_fname, be.bstrerror());
941 * Based on the filetype perform the correct action. We support most filetypes here, more
942 * then the actual implementation on Solaris supports so some code may never get executed
943 * due to limitations in the implementation.
945 switch (st.st_mode & S_IFMT) {
950 * Get any acl on the xattr.
952 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok)
956 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
957 * Encode the stat struct into an ASCII representation.
959 encode_stat(attribs, &st, 0, stream);
960 cnt = snprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
961 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
966 * Get any acl on the xattr.
968 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok)
972 * See if this is the toplevel_hidden_dir being saved.
974 if (toplevel_hidden_dir) {
976 * Save the data for later storage when we encounter a real xattr.
977 * Encode the stat struct into an ASCII representation and jump out of the function.
979 encode_stat(attribs, &st, 0, stream);
980 toplevel_hidden_dir_xattr_data_len = snprintf(toplevel_hidden_dir_xattr_data,
981 sizeof(toplevel_hidden_dir_xattr_data),
983 target_attrname, 0, attribs, 0,
984 (acl_text) ? acl_text : "", 0);
988 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
989 * Encode the stat struct into an ASCII representation.
991 encode_stat(attribs, &st, 0, stream);
992 cnt = snprintf(buffer, sizeof(buffer),
994 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
999 * If this is a hardlinked file check the inode cache for a hit.
1001 if (st.st_nlink > 1) {
1003 * See if the cache already knows this inode number.
1005 if ((xlce = find_xattr_link_cache_entry(st.st_ino)) != NULL) {
1007 * Generate a xattr encoding with the reference to the target in there.
1009 encode_stat(attribs, &st, st.st_ino, stream);
1010 cnt = snprintf(buffer, sizeof(buffer),
1012 target_attrname, 0, attribs, 0, xlce->target, 0);
1013 pm_memcpy(jcr->xattr_data, buffer, cnt);
1014 jcr->xattr_data_len = cnt;
1015 retval = send_xattr_stream(jcr, stream);
1018 * For a hard linked file we are ready now, no need to recursively save the attributes.
1024 * Store this hard linked file in the cache.
1025 * Store the name relative to the top level xattr space.
1027 add_xattr_link_cache_entry(st.st_ino, target_attrname + 1);
1031 * Get any acl on the xattr.
1033 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok) {
1038 * Encode the stat struct into an ASCII representation.
1040 encode_stat(attribs, &st, 0, stream);
1041 cnt = snprintf(buffer, sizeof(buffer),
1043 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1046 * Open the extended or extensible attribute file.
1048 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1054 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1055 target_attrname, jcr->last_fname, be.bstrerror());
1056 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1057 target_attrname, jcr->last_fname, be.bstrerror());
1065 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1066 * Encode the stat struct into an ASCII representation.
1068 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1074 Jmsg3(jcr, M_ERROR, 0, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1075 target_attrname, jcr->last_fname, be.bstrerror());
1076 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1077 target_attrname, jcr->last_fname, be.bstrerror());
1083 * Generate a xattr encoding with the reference to the target in there.
1085 encode_stat(attribs, &st, st.st_ino, stream);
1086 cnt = snprintf(buffer, sizeof(buffer),
1088 target_attrname, 0, attribs, 0, link_source, 0);
1089 pm_memcpy(jcr->xattr_data, buffer, cnt);
1090 jcr->xattr_data_len = cnt;
1091 retval = send_xattr_stream(jcr, stream);
1094 * For a soft linked file we are ready now, no need to recursively save the attributes.
1103 * See if this is the first real xattr being saved. If it is save the toplevel_hidden_dir attributes first.
1105 if (nr_xattr_saved == 0) {
1106 pm_memcpy(jcr->xattr_data, toplevel_hidden_dir_xattr_data, toplevel_hidden_dir_xattr_data_len);
1107 jcr->xattr_data_len = toplevel_hidden_dir_xattr_data_len;
1108 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1111 pm_memcpy(jcr->xattr_data, buffer, cnt);
1112 jcr->xattr_data_len = cnt;
1115 * Only dump the content of regular files.
1117 switch (st.st_mode & S_IFMT) {
1119 if (st.st_size > 0) {
1121 * Protect ourself against things getting out of hand.
1123 if (st.st_size >= MAX_XATTR_STREAM) {
1124 Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1125 jcr->last_fname, MAX_XATTR_STREAM);
1129 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1130 jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, jcr->xattr_data_len + cnt);
1131 memcpy(jcr->xattr_data + jcr->xattr_data_len, buffer, cnt);
1132 jcr->xattr_data_len += cnt;
1136 Jmsg2(jcr, M_ERROR, 0, _("Unable to read content of xattr %s on file \"%s\"\n"),
1137 target_attrname, jcr->last_fname);
1138 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1139 target_attrname, jcr->last_fname);
1150 retval = send_xattr_stream(jcr, stream);
1155 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1156 * available on this extended attribute.
1159 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1162 * The recursive call could change our working dir so change back to the wanted workdir.
1164 if (fchdir(fd) < 0) {
1170 Jmsg2(jcr, M_ERROR, 0, _("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;
1199 * Determine what argument to use. Use attr_parent when set
1200 * (recursive call) or jcr->last_fname for first call. Also save
1201 * the current depth of the xattr_space we are in.
1205 if (xattr_namespace) {
1206 snprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1207 xattr_namespace, attr_parent);
1209 strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1212 name = jcr->last_fname;
1213 strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1217 * Open the file on which to save the xattrs read-only.
1219 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1225 Jmsg2(jcr, M_ERROR, 0, _("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;
1250 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1251 name, jcr->last_fname, be.bstrerror());
1252 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1253 name, jcr->last_fname, be.bstrerror());
1259 * We need to change into the attribute directory to determine if each of the
1260 * attributes should be saved.
1262 if (fchdir(attrdirfd) < 0) {
1264 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1265 jcr->last_fname, be.bstrerror());
1266 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1267 jcr->last_fname, attrdirfd, be.bstrerror());
1272 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1273 * else because the readdir returns "." entry after the extensible attr entry.
1274 * And as we want this entry before anything else we better just save its data.
1277 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1278 true, STREAM_XATTR_SOLARIS);
1280 if ((fd = dup(attrdirfd)) == -1 ||
1281 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1283 Jmsg2(jcr, M_ERROR, 0, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1284 jcr->last_fname, be.bstrerror());
1285 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1286 jcr->last_fname, fd, be.bstrerror());
1292 * Walk the namespace.
1294 while (dp = readdir(dirp)) {
1296 * Skip only the toplevel . dir.
1298 if (!attr_parent && !strcmp(dp->d_name, "."))
1302 * Skip all .. directories
1304 if (!strcmp(dp->d_name, ".."))
1307 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1308 current_xattr_namespace, dp->d_name, jcr->last_fname);
1310 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1312 * We are not interested in read-only extensible attributes.
1314 if (!strcmp(dp->d_name, VIEW_READONLY)) {
1315 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1316 current_xattr_namespace, dp->d_name, jcr->last_fname);
1322 * We are only interested in read-write extensible attributes
1323 * when they contain non-transient values.
1325 if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1327 * Determine if there are non-transient system attributes at the toplevel.
1328 * We need to provide a fd to the open file.
1330 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1331 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1332 current_xattr_namespace, dp->d_name, jcr->last_fname);
1339 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1340 false, STREAM_XATTR_SOLARIS_SYS);
1343 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1348 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1349 false, STREAM_XATTR_SOLARIS);
1353 retval = bsub_exit_ok;
1356 if (attrdirfd != -1)
1364 static bsub_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1366 #ifdef HAVE_EXTENDED_ACL
1370 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1371 Jmsg1(jcr, M_ERROR, 0, _("Unable to convert acl from text on file \"%s\"\n"),
1373 return bsub_exit_nok;
1376 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1377 acl_set(attrname, aclp) != 0) {
1379 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1380 attrname, jcr->last_fname, be.bstrerror());
1381 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1382 attrname, jcr->last_fname, be.bstrerror());
1383 return bsub_exit_nok;
1389 return bsub_exit_ok;
1391 #else /* HAVE_EXTENDED_ACL */
1393 aclent_t *acls = NULL;
1395 acls = aclfromtext(acl_text, &n);
1397 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1398 acl(attrname, SETACL, n, acls) != 0) {
1400 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1401 attrname, jcr->last_fname, be.bstrerror());
1402 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1403 attrname, jcr->last_fname, be.bstrerror());
1404 return bsub_exit_nok;
1411 return bsub_exit_ok;
1413 #endif /* HAVE_EXTENDED_ACL */
1416 #endif /* HAVE_ACL */
1418 static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1420 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1421 int used_bytes, total_bytes, cnt;
1422 char *bp, *target_attrname, *attribs;
1423 char *linked_target = NULL;
1424 char *acl_text = NULL;
1428 struct timeval times[2];
1429 bsub_exit_code retval = bsub_exit_nok;
1432 * Parse the xattr stream. First the part that is the same for all xattrs.
1435 total_bytes = jcr->xattr_data_len;
1438 * The name of the target xattr has a leading / we are not interested
1439 * in that so skip it when decoding the string. We always start a the /
1440 * of the xattr space anyway.
1442 target_attrname = jcr->xattr_data + 1;
1443 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1444 (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1450 * Open the file on which to restore the xattrs read-only.
1452 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1454 Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1455 jcr->last_fname, be.bstrerror());
1456 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1457 jcr->last_fname, be.bstrerror());
1462 * Open the xattr naming space and make it the current working dir.
1464 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1466 Jmsg2(jcr, M_ERROR, 0, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1467 jcr->last_fname, be.bstrerror());
1468 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1469 jcr->last_fname, be.bstrerror());
1473 if (fchdir(attrdirfd) < 0) {
1475 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1476 jcr->last_fname, be.bstrerror());
1477 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1478 jcr->last_fname, attrdirfd, be.bstrerror());
1483 * Try to open the correct xattr subdir based on the target_attrname given.
1484 * e.g. check if its a subdir attrname. Each / in the string makes us go
1487 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1490 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1492 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1493 target_attrname, jcr->last_fname, be.bstrerror());
1494 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1495 target_attrname, jcr->last_fname, be.bstrerror());
1503 * Open the xattr naming space.
1505 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1507 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1508 target_attrname, jcr->last_fname, be.bstrerror());
1509 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1510 target_attrname, jcr->last_fname, be.bstrerror());
1518 * Make the xattr space our current workingdir.
1520 if (fchdir(attrdirfd) < 0) {
1522 Jmsg3(jcr, M_ERROR, 0, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1523 target_attrname, jcr->last_fname, be.bstrerror());
1524 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1525 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1529 target_attrname = ++bp;
1533 * Decode the attributes from the stream.
1535 decode_stat(attribs, &st, &inum);
1538 * Decode the next field (acl_text).
1540 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1541 (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1547 * Based on the filetype perform the correct action. We support most filetypes here, more
1548 * then the actual implementation on Solaris supports so some code may never get executed
1549 * due to limitations in the implementation.
1551 switch (st.st_mode & S_IFMT) {
1554 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1556 unlinkat(attrdirfd, target_attrname, 0);
1557 if (mkfifo(target_attrname, st.st_mode) < 0) {
1559 Jmsg3(jcr, M_ERROR, 0, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1560 target_attrname, jcr->last_fname, be.bstrerror());
1561 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1562 target_attrname, jcr->last_fname, be.bstrerror());
1569 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1571 unlinkat(attrdirfd, target_attrname, 0);
1572 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1574 Jmsg3(jcr, M_ERROR, 0, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1575 target_attrname, jcr->last_fname, be.bstrerror());
1576 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1577 target_attrname, jcr->last_fname, be.bstrerror());
1583 * If its not the hidden_dir create the entry.
1584 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1586 if (strcmp(target_attrname, ".")) {
1587 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1588 if (mkdir(target_attrname, st.st_mode) < 0) {
1590 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1591 target_attrname, jcr->last_fname, be.bstrerror());
1592 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1593 target_attrname, jcr->last_fname, be.bstrerror());
1600 * See if this is a hard linked file. e.g. inum != 0
1605 unlinkat(attrdirfd, target_attrname, 0);
1606 if (link(linked_target, target_attrname) < 0) {
1608 Jmsg4(jcr, M_ERROR, 0, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1609 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1610 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1611 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1616 * Successfully restored xattr.
1618 retval = bsub_exit_ok;
1621 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1622 (used_bytes = (bp - jcr->xattr_data)) >= total_bytes) {
1626 if (used_bytes < (total_bytes - 1))
1630 * Restore the actual xattr.
1632 if (!is_extensible) {
1633 unlinkat(attrdirfd, target_attrname, 0);
1636 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1638 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1639 target_attrname, jcr->last_fname, be.bstrerror());
1640 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1641 target_attrname, jcr->last_fname, be.bstrerror());
1647 * Restore the actual data.
1649 if (st.st_size > 0) {
1650 used_bytes = (data - jcr->xattr_data);
1651 cnt = total_bytes - used_bytes;
1654 * Do a sanity check, the st.st_size should be the same as the number of bytes
1655 * we have available as data of the stream.
1657 if (cnt != st.st_size) {
1658 Jmsg2(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
1659 target_attrname, jcr->last_fname);
1660 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1661 target_attrname, jcr->last_fname);
1666 cnt = write(attrfd, data, cnt);
1669 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
1670 target_attrname, jcr->last_fname, be.bstrerror());
1671 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
1672 target_attrname, jcr->last_fname, be.bstrerror());
1678 cnt = total_bytes - used_bytes;
1684 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1688 if (symlink(linked_target, target_attrname) < 0) {
1690 Jmsg4(jcr, M_ERROR, 0, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
1691 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1692 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
1693 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1698 * Successfully restored xattr.
1700 retval = bsub_exit_ok;
1707 * Restore owner and acl for non extensible attributes.
1709 if (!is_extensible) {
1710 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
1714 * Gentile way of the system saying this type of xattr layering is not supported.
1715 * But as this is not an error we return a positive return value.
1717 retval = bsub_exit_ok;
1721 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1722 target_attrname, jcr->last_fname, be.bstrerror());
1723 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1724 target_attrname, jcr->last_fname, be.bstrerror());
1731 if (acl_text && *acl_text)
1732 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bsub_exit_ok)
1734 #endif /* HAVE_ACL */
1737 * For a non extensible attribute restore access and modification time on the xattr.
1739 if (!is_extensible) {
1740 times[0].tv_sec = st.st_atime;
1741 times[0].tv_usec = 0;
1742 times[1].tv_sec = st.st_mtime;
1743 times[1].tv_usec = 0;
1745 if (futimesat(attrdirfd, target_attrname, times) < 0) {
1747 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
1748 target_attrname, jcr->last_fname, be.bstrerror());
1749 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
1750 target_attrname, jcr->last_fname, be.bstrerror());
1756 * Successfully restored xattr.
1758 retval = bsub_exit_ok;
1762 Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
1764 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
1771 if (attrdirfd != -1) {
1780 static bsub_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt, int default_stream)
1783 bsub_exit_code retval = bsub_exit_ok;
1786 * First see if extended attributes or extensible attributes are present.
1787 * If not just pretend things went ok.
1789 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1793 * As we change the cwd in the save function save the current cwd
1794 * for restore after return from the solaris_save_xattrs function.
1796 xattr_link_cache = New(alist(10, not_owned_by_alist));
1797 getcwd(cwd, sizeof(cwd));
1798 retval = solaris_save_xattrs(jcr, NULL, NULL);
1800 delete xattr_link_cache;
1801 xattr_link_cache = NULL;
1806 static bsub_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
1809 bool is_extensible = false;
1810 bsub_exit_code retval;
1813 * First make sure we can restore xattr on the filesystem.
1816 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1817 case STREAM_XATTR_SOLARIS_SYS:
1818 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1819 Qmsg1(jcr, M_WARNING, 0,
1820 _("Failed to restore extensible attributes on file \"%s\"\n"),
1822 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1824 return bsub_exit_nok;
1827 is_extensible = true;
1830 case STREAM_XATTR_SOLARIS:
1831 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1832 Qmsg1(jcr, M_WARNING, 0,
1833 _("Failed to restore extended attributes on file \"%s\"\n"),
1835 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1837 return bsub_exit_nok;
1841 return bsub_exit_nok;
1845 * As we change the cwd in the restore function save the current cwd
1846 * for restore after return from the solaris_restore_xattrs function.
1848 getcwd(cwd, sizeof(cwd));
1849 retval = solaris_restore_xattrs(jcr, is_extensible);
1856 * Function pointers to the build and parse function to use for these xattrs.
1858 static bsub_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt, int default_stream) = solaris_build_xattr_streams;
1859 static bsub_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
1861 #endif /* defined(HAVE_SUN_OS) */
1863 bsub_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1865 if (os_build_xattr_streams) {
1866 return (*os_build_xattr_streams)(jcr, ff_pkt, os_default_xattr_streams[0]);
1868 return bsub_exit_nok;
1871 bsub_exit_code parse_xattr_streams(JCR *jcr, int stream)
1875 if (os_parse_xattr_streams) {
1877 * See if we can parse this stream, and ifso give it a try.
1879 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
1880 if (os_default_xattr_streams[cnt] == stream) {
1881 return (*os_parse_xattr_streams)(jcr, stream);
1886 * Issue a warning and discard the message. But pretend the restore was ok.
1888 Jmsg2(jcr, M_WARNING, 0,
1889 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1890 jcr->last_fname, stream);
1891 return bsub_exit_nok;