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 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
131 * listxattr, getxattr and setxattr with an extra options argument
132 * which mimics the l variants of the functions when we specify
133 * XATTR_NOFOLLOW as the options value.
135 #if defined(HAVE_DARWIN_OS)
136 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
137 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
138 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
141 * Fallback to the non l-functions when those are not available.
143 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
144 #define lgetxattr getxattr
146 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
147 #define lsetxattr setxattr
149 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
150 #define llistxattr listxattr
154 static void xattr_drop_internal_table(xattr_t *xattr_value_list)
156 xattr_t *current_xattr;
159 * Walk the list of xattrs and free allocated memory on traversing.
161 for (current_xattr = xattr_value_list;
162 current_xattr != (xattr_t *)NULL;
165 * See if we can shortcut.
167 if (current_xattr->magic != XATTR_MAGIC)
170 free(current_xattr->name);
172 if (current_xattr->value_length > 0)
173 free(current_xattr->value);
177 * Free the array of control structs.
179 free(xattr_value_list);
183 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
184 * which encodes one or more xattr_t structures.
186 * The Serialized stream consists of the following elements:
187 * magic - A magic string which makes it easy to detect any binary incompatabilites
188 * name_length - The length of the following xattr name
189 * name - The name of the extended attribute
190 * value_length - The length of the following xattr data
191 * value - The actual content of the extended attribute
193 * This is repeated 1 or more times.
196 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list)
198 xattr_t *current_xattr;
202 * Make sure the serialized stream fits in the poolmem buffer.
203 * We allocate some more to be sure the stream is gonna fit.
205 jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, expected_serialize_len + 10);
206 ser_begin(jcr->xattr_data, expected_serialize_len + 10);
209 * Walk the list of xattrs and serialize the data.
211 for (current_xattr = xattr_value_list; current_xattr != (xattr_t *)NULL; current_xattr++) {
213 * See if we can shortcut.
215 if (current_xattr->magic != XATTR_MAGIC)
218 ser_uint32(current_xattr->magic);
219 ser_uint32(current_xattr->name_length);
220 ser_bytes(current_xattr->name, current_xattr->name_length);
222 ser_uint32(current_xattr->value_length);
223 ser_bytes(current_xattr->value, current_xattr->value_length);
226 ser_end(jcr->xattr_data, expected_serialize_len + 10);
227 jcr->xattr_data_len = ser_length(jcr->xattr_data);
228 return jcr->xattr_data_len;
231 static bsub_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int default_stream)
234 int32_t xattr_list_len,
236 uint32_t expected_serialize_len = 0;
237 char *xattr_list, *bp;
238 xattr_t *xattr_value_list, *current_xattr;
241 * First get the length of the available list with extended attributes.
243 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
244 if (xattr_list_len < 0) {
247 return bsub_exit_nok;
250 Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
251 jcr->last_fname, be.bstrerror());
252 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
253 jcr->last_fname, be.bstrerror());
254 return bsub_exit_nok;
256 } else if (xattr_list_len == 0) {
261 * Allocate room for the extented attribute list.
263 xattr_list = (char *)malloc(xattr_list_len + 1);
264 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
267 * Get the actual list of extended attributes names for a file.
269 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
270 if (xattr_list_len < 0) {
274 return bsub_exit_nok;
277 Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
278 jcr->last_fname, be.bstrerror());
279 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
280 jcr->last_fname, be.bstrerror());
282 return bsub_exit_nok;
285 xattr_list[xattr_list_len] = '\0';
288 * Count the number of extended attributes on a file.
291 while ((bp - xattr_list) + 1 < xattr_list_len) {
292 #if defined(HAVE_LINUX_OS)
294 * On Linux you also get the acls in the extented attribute list.
295 * So we check if we are already backing up acls and if we do we
296 * don't store the extended attribute with the same info.
298 if ((ff_pkt->flags & FO_ACL) == 0 || strcmp(bp, "system.posix_acl_access"))
304 bp = strchr(bp, '\0') + 1;
313 * Allocate enough room to hold all extended attributes.
314 * After allocating the storage make sure its empty by zeroing it.
316 xattr_value_list = (xattr_t *)malloc(count * sizeof(xattr_t));
317 memset((caddr_t)xattr_value_list, 0, count * sizeof(xattr_t));
320 * Walk the list of extended attributes names and retrieve the data.
321 * We already count the bytes needed for serializing the stream later on.
323 current_xattr = xattr_value_list;
325 while ((bp - xattr_list) + 1 < xattr_list_len) {
326 #if defined(HAVE_LINUX_OS)
327 if (ff_pkt->flags & FO_ACL && !strcmp(bp, "system.posix_acl_access")) {
328 bp = strchr(bp, '\0') + 1;
334 * Each xattr valuepair starts with a magic so we can parse it easier.
336 current_xattr->magic = XATTR_MAGIC;
337 expected_serialize_len += sizeof(current_xattr->magic);
340 * Allocate space for storing the name.
342 current_xattr->name_length = strlen(bp);
343 current_xattr->name = (char *)malloc(current_xattr->name_length);
344 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
346 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
349 * First see how long the value is for the extended attribute.
351 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
352 if (xattr_value_len < 0) {
358 Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
359 jcr->last_fname, be.bstrerror());
360 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
361 jcr->last_fname, be.bstrerror());
367 * Allocate space for storing the value.
369 current_xattr->value = (char *)malloc(xattr_value_len);
370 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
372 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
373 if (xattr_value_len < 0) {
379 Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
380 jcr->last_fname, be.bstrerror());
381 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
382 jcr->last_fname, be.bstrerror());
388 * Store the actual length of the value.
390 current_xattr->value_length = xattr_value_len;
391 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
394 * Protect ourself against things getting out of hand.
396 if (expected_serialize_len >= MAX_XATTR_STREAM) {
397 Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
398 jcr->last_fname, MAX_XATTR_STREAM);
406 bp = strchr(bp, '\0') + 1;
410 * Serialize the datastream.
412 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
413 Jmsg1(jcr, M_ERROR, 0, _("Failed to serialize extended attributes on file \"%s\"\n"),
415 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
420 xattr_drop_internal_table(xattr_value_list);
424 * Send the datastream to the SD.
426 return send_xattr_stream(jcr, default_stream);
429 xattr_drop_internal_table(xattr_value_list);
431 return bsub_exit_nok;
434 static bsub_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
437 xattr_t current_xattr;
438 bsub_exit_code retval = bsub_exit_nok;
441 * Parse the stream and perform the setxattr calls on the file.
443 * Start unserializing the data. We keep on looping while we have not
444 * unserialized all bytes in the stream.
446 unser_begin(jcr->xattr_data, jcr->xattr_data_len);
447 while (unser_length(jcr->xattr_data) < jcr->xattr_data_len) {
449 * First make sure the magic is present. This way we can easily catch corruption.
450 * Any missing MAGIC is fatal we do NOT try to continue.
452 unser_uint32(current_xattr.magic);
453 if (current_xattr.magic != XATTR_MAGIC) {
454 Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
456 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
458 return bsub_exit_nok;
462 * Decode the valuepair. First decode the length of the name.
464 unser_uint32(current_xattr.name_length);
467 * Allocate room for the name and decode its content.
469 current_xattr.name = (char *)malloc(current_xattr.name_length + 1);
470 unser_bytes(current_xattr.name, current_xattr.name_length);
473 * The xattr_name needs to be null terminated for lsetxattr.
475 current_xattr.name[current_xattr.name_length] = '\0';
478 * Decode the value length.
480 unser_uint32(current_xattr.value_length);
483 * Allocate room for the value and decode its content.
485 current_xattr.value = (char *)malloc(current_xattr.value_length);
486 unser_bytes(current_xattr.value, current_xattr.value_length);
489 * Try to set the extended attribute on the file.
490 * If we fail to set this attribute we flag the error but its not fatal,
491 * we try to restore the other extended attributes too.
493 if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
498 current_xattr.value_length, 0) != 0) {
500 Jmsg2(jcr, M_ERROR, 0, _("lsetxattr error on file \"%s\": ERR=%s\n"),
501 jcr->last_fname, be.bstrerror());
502 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
503 jcr->last_fname, be.bstrerror());
509 * Free the temporary buffers.
511 free(current_xattr.name);
512 free(current_xattr.value);
515 unser_end(jcr->xattr_data, jcr->xattr_data_len);
520 * For all these os-es setup the build and parse function pointer to the generic functions.
522 static bsub_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt, int default_stream) = generic_xattr_build_streams;
523 static bsub_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
526 * All these os-es have 1 xattr stream.
528 #if defined(HAVE_DARWIN_OS)
529 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
530 #elif defined(HAVE_FREEBSD_OS)
531 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
532 #elif defined(HAVE_LINUX_OS)
533 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
534 #elif defined(HAVE_NETBSD_OS)
535 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
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 * This is the count of xattrs saved on a certain file, it gets reset
636 * on each new file processed and is used to see if we need to send
637 * the hidden xattr dir data. We only send that data when we encounter
638 * an other xattr on the file.
640 static int nr_xattr_saved = 0;
641 static char toplevel_hidden_dir_xattr_data[MAXSTRING];
642 static int toplevel_hidden_dir_xattr_data_len;
645 * This code creates a temporary cache with entries for each xattr which has
646 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
648 static alist *xattr_link_cache = NULL;
650 static struct xattr_link_cache_entry *find_xattr_link_cache_entry(ino_t inum)
652 xattr_link_cache_entry_t *ptr;
654 foreach_alist(ptr, xattr_link_cache) {
655 if (ptr && ptr->inum == inum) {
662 static void add_xattr_link_cache_entry(ino_t inum, char *target)
664 xattr_link_cache_entry_t *ptr;
666 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(struct xattr_link_cache_entry));
667 memset((caddr_t)ptr, 0, sizeof(struct xattr_link_cache_entry));
669 strncpy(ptr->target, target, sizeof(ptr->target));
670 xattr_link_cache->append(ptr);
673 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
675 * This function returns true if a non default extended system attribute
676 * list is associated with fd and returns false when an error has occured
677 * or when only extended system attributes other than archive,
678 * av_modified or crtime are set.
680 * The function returns true for the following cases:
682 * - any extended system attribute other than the default attributes
683 * ('archive', 'av_modified' and 'crtime') is set
684 * - nvlist has NULL name string
685 * - nvpair has data type of 'nvlist'
686 * - default data type.
688 static bool solaris_has_non_transient_extensible_attributes(int fd)
698 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
703 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
704 name = nvpair_name(pair);
707 fattr = name_to_attr(name);
713 type = nvpair_type(pair);
715 case DATA_TYPE_BOOLEAN_VALUE:
716 if (nvpair_value_boolean_value(pair, &value) != 0) {
719 if (value && fattr != F_ARCHIVE &&
720 fattr != F_AV_MODIFIED) {
725 case DATA_TYPE_UINT64_ARRAY:
726 if (fattr != F_CRTIME) {
731 case DATA_TYPE_NVLIST:
739 if (response != NULL) {
740 nvlist_free(response);
744 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
746 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
748 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
749 * There is no need to store those acls as we already store the stat bits too.
751 static bool acl_is_trivial(int count, aclent_t *entries)
756 for (n = 0; n < count; n++) {
758 if (!(ace->a_type == USER_OBJ ||
759 ace->a_type == GROUP_OBJ ||
760 ace->a_type == OTHER_OBJ ||
761 ace->a_type == CLASS_OBJ))
766 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
768 static bsub_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
771 #ifdef HAVE_EXTENDED_ACL
776 * See if this attribute has an ACL
778 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
779 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
781 * See if there is a non trivial acl on the file.
783 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
784 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
787 return bsub_exit_nok;
790 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
791 attrname, jcr->last_fname, be.bstrerror());
792 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
793 attrname, jcr->last_fname, be.bstrerror());
794 return bsub_exit_nok;
799 #if defined(ACL_SID_FMT)
801 * New format flag added in newer Solaris versions.
803 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
805 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
806 #endif /* ACL_SID_FMT */
808 *acl_text = acl_totext(aclp, flags);
817 #else /* HAVE_EXTENDED_ACL */
819 aclent_t *acls = NULL;
822 * See if this attribute has an ACL
825 n = facl(fd, GETACLCNT, 0, NULL);
827 n = acl(attrname, GETACLCNT, 0, NULL);
830 if (n >= MIN_ACL_ENTRIES) {
831 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
832 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
833 acl(attrname, GETACL, n, acls) != n) {
837 return bsub_exit_nok;
840 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
841 attrname, jcr->last_fname, be.bstrerror());
842 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
843 attrname, jcr->last_fname, be.bstrerror());
845 return bsub_exit_nok;
850 * See if there is a non trivial acl on the file.
852 if (!acl_is_trivial(n, acls)) {
853 if ((*acl_text = acltotext(acls, n)) == NULL) {
855 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
856 attrname, jcr->last_fname, be.bstrerror());
857 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
858 attrname, jcr->last_fname, be.bstrerror());
860 return bsub_exit_nok;
871 #endif /* HAVE_EXTENDED_ACL */
875 #endif /* HAVE_ACL */
879 * Forward declaration for recursive function call.
881 static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
884 * Save an extended or extensible attribute.
885 * This is stored as an opaque stream of bytes with the following encoding:
887 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
889 * or for a hardlinked or symlinked attribute
891 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
893 * xattr_name can be a subpath relative to the file the xattr is on.
894 * stat_buffer is the string representation of the stat struct.
895 * acl_string is an acl text when a non trivial acl is set on the xattr.
896 * actual_xattr_data is the content of the xattr file.
898 static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
899 const char *attrname, bool toplevel_hidden_dir, int stream)
904 struct xattr_link_cache_entry *xlce;
905 char target_attrname[PATH_MAX];
906 char link_source[PATH_MAX];
907 char *acl_text = NULL;
908 char attribs[MAXSTRING];
910 bsub_exit_code retval = bsub_exit_nok;
912 snprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
915 * Get the stats of the extended or extensible attribute.
917 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
923 Jmsg3(jcr, M_ERROR, 0, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
924 target_attrname, jcr->last_fname, be.bstrerror());
925 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
926 target_attrname, jcr->last_fname, be.bstrerror());
932 * Based on the filetype perform the correct action. We support most filetypes here, more
933 * then the actual implementation on Solaris supports so some code may never get executed
934 * due to limitations in the implementation.
936 switch (st.st_mode & S_IFMT) {
941 * Get any acl on the xattr.
943 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok)
947 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
948 * Encode the stat struct into an ASCII representation.
950 encode_stat(attribs, &st, 0, stream);
951 cnt = snprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
952 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
957 * Get any acl on the xattr.
959 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok)
963 * See if this is the toplevel_hidden_dir being saved.
965 if (toplevel_hidden_dir) {
967 * Save the data for later storage when we encounter a real xattr.
968 * Encode the stat struct into an ASCII representation and jump out of the function.
970 encode_stat(attribs, &st, 0, stream);
971 toplevel_hidden_dir_xattr_data_len = snprintf(toplevel_hidden_dir_xattr_data,
972 sizeof(toplevel_hidden_dir_xattr_data),
974 target_attrname, 0, attribs, 0,
975 (acl_text) ? acl_text : "", 0);
979 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
980 * Encode the stat struct into an ASCII representation.
982 encode_stat(attribs, &st, 0, stream);
983 cnt = snprintf(buffer, sizeof(buffer),
985 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
990 * If this is a hardlinked file check the inode cache for a hit.
992 if (st.st_nlink > 1) {
994 * See if the cache already knows this inode number.
996 if ((xlce = find_xattr_link_cache_entry(st.st_ino)) != NULL) {
998 * Generate a xattr encoding with the reference to the target in there.
1000 encode_stat(attribs, &st, st.st_ino, stream);
1001 cnt = snprintf(buffer, sizeof(buffer),
1003 target_attrname, 0, attribs, 0, xlce->target, 0);
1004 pm_memcpy(jcr->xattr_data, buffer, cnt);
1005 jcr->xattr_data_len = cnt;
1006 retval = send_xattr_stream(jcr, stream);
1009 * For a hard linked file we are ready now, no need to recursively save the attributes.
1015 * Store this hard linked file in the cache.
1016 * Store the name relative to the top level xattr space.
1018 add_xattr_link_cache_entry(st.st_ino, target_attrname + 1);
1022 * Get any acl on the xattr.
1024 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok) {
1029 * Encode the stat struct into an ASCII representation.
1031 encode_stat(attribs, &st, 0, stream);
1032 cnt = snprintf(buffer, sizeof(buffer),
1034 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1037 * Open the extended or extensible attribute file.
1039 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1045 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1046 target_attrname, jcr->last_fname, be.bstrerror());
1047 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1048 target_attrname, jcr->last_fname, be.bstrerror());
1056 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1057 * Encode the stat struct into an ASCII representation.
1059 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1065 Jmsg3(jcr, M_ERROR, 0, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1066 target_attrname, jcr->last_fname, be.bstrerror());
1067 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1068 target_attrname, jcr->last_fname, be.bstrerror());
1074 * Generate a xattr encoding with the reference to the target in there.
1076 encode_stat(attribs, &st, st.st_ino, stream);
1077 cnt = snprintf(buffer, sizeof(buffer),
1079 target_attrname, 0, attribs, 0, link_source, 0);
1080 pm_memcpy(jcr->xattr_data, buffer, cnt);
1081 jcr->xattr_data_len = cnt;
1082 retval = send_xattr_stream(jcr, stream);
1085 * For a soft linked file we are ready now, no need to recursively save the attributes.
1094 * See if this is the first real xattr being saved. If it is save the toplevel_hidden_dir attributes first.
1096 if (nr_xattr_saved == 0) {
1097 pm_memcpy(jcr->xattr_data, toplevel_hidden_dir_xattr_data, toplevel_hidden_dir_xattr_data_len);
1098 jcr->xattr_data_len = toplevel_hidden_dir_xattr_data_len;
1099 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1102 pm_memcpy(jcr->xattr_data, buffer, cnt);
1103 jcr->xattr_data_len = cnt;
1106 * Only dump the content of regular files.
1108 switch (st.st_mode & S_IFMT) {
1110 if (st.st_size > 0) {
1112 * Protect ourself against things getting out of hand.
1114 if (st.st_size >= MAX_XATTR_STREAM) {
1115 Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1116 jcr->last_fname, MAX_XATTR_STREAM);
1120 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1121 jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, jcr->xattr_data_len + cnt);
1122 memcpy(jcr->xattr_data + jcr->xattr_data_len, buffer, cnt);
1123 jcr->xattr_data_len += cnt;
1127 Jmsg2(jcr, M_ERROR, 0, _("Unable to read content of xattr %s on file \"%s\"\n"),
1128 target_attrname, jcr->last_fname);
1129 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1130 target_attrname, jcr->last_fname);
1141 retval = send_xattr_stream(jcr, stream);
1146 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1147 * available on this extended attribute.
1150 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1153 * The recursive call could change our working dir so change back to the wanted workdir.
1155 if (fchdir(fd) < 0) {
1161 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1162 jcr->last_fname, be.bstrerror());
1163 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1164 jcr->last_fname, fd, be.bstrerror());
1180 static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1183 int fd, filefd = -1, attrdirfd = -1;
1186 char current_xattr_namespace[PATH_MAX];
1187 bsub_exit_code retval = bsub_exit_nok;
1190 * Determine what argument to use. Use attr_parent when set
1191 * (recursive call) or jcr->last_fname for first call. Also save
1192 * the current depth of the xattr_space we are in.
1196 if (xattr_namespace) {
1197 snprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1198 xattr_namespace, attr_parent);
1200 strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1203 name = jcr->last_fname;
1204 strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1208 * Open the file on which to save the xattrs read-only.
1210 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1216 Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1217 jcr->last_fname, be.bstrerror());
1218 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1219 jcr->last_fname, be.bstrerror());
1225 * Open the xattr naming space.
1227 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1231 * Gentile way of the system saying this type of xattr layering is not supported.
1232 * Which is not problem we just forget about this this xattr.
1233 * But as this is not an error we return a positive return value.
1235 retval = bsub_exit_ok;
1241 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1242 name, jcr->last_fname, be.bstrerror());
1243 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1244 name, jcr->last_fname, be.bstrerror());
1250 * We need to change into the attribute directory to determine if each of the
1251 * attributes should be saved.
1253 if (fchdir(attrdirfd) < 0) {
1255 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1256 jcr->last_fname, be.bstrerror());
1257 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1258 jcr->last_fname, attrdirfd, be.bstrerror());
1263 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1264 * else because the readdir returns "." entry after the extensible attr entry.
1265 * And as we want this entry before anything else we better just save its data.
1268 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1269 true, STREAM_XATTR_SOLARIS);
1271 if ((fd = dup(attrdirfd)) == -1 ||
1272 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1274 Jmsg2(jcr, M_ERROR, 0, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1275 jcr->last_fname, be.bstrerror());
1276 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1277 jcr->last_fname, fd, be.bstrerror());
1283 * Walk the namespace.
1285 while (dp = readdir(dirp)) {
1287 * Skip only the toplevel . dir.
1289 if (!attr_parent && !strcmp(dp->d_name, "."))
1293 * Skip all .. directories
1295 if (!strcmp(dp->d_name, ".."))
1298 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1299 current_xattr_namespace, dp->d_name, jcr->last_fname);
1301 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1303 * We are not interested in read-only extensible attributes.
1305 if (!strcmp(dp->d_name, VIEW_READONLY)) {
1306 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1307 current_xattr_namespace, dp->d_name, jcr->last_fname);
1313 * We are only interested in read-write extensible attributes
1314 * when they contain non-transient values.
1316 if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1318 * Determine if there are non-transient system attributes at the toplevel.
1319 * We need to provide a fd to the open file.
1321 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1322 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1323 current_xattr_namespace, dp->d_name, jcr->last_fname);
1330 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1331 false, STREAM_XATTR_SOLARIS_SYS);
1334 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1339 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1340 false, STREAM_XATTR_SOLARIS);
1344 retval = bsub_exit_ok;
1347 if (attrdirfd != -1)
1355 static bsub_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1357 #ifdef HAVE_EXTENDED_ACL
1361 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1362 Jmsg1(jcr, M_ERROR, 0, _("Unable to convert acl from text on file \"%s\"\n"),
1364 return bsub_exit_nok;
1367 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1368 acl_set(attrname, aclp) != 0) {
1370 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1371 attrname, jcr->last_fname, be.bstrerror());
1372 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1373 attrname, jcr->last_fname, be.bstrerror());
1374 return bsub_exit_nok;
1380 return bsub_exit_ok;
1382 #else /* HAVE_EXTENDED_ACL */
1384 aclent_t *acls = NULL;
1386 acls = aclfromtext(acl_text, &n);
1388 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1389 acl(attrname, SETACL, n, acls) != 0) {
1391 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1392 attrname, jcr->last_fname, be.bstrerror());
1393 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1394 attrname, jcr->last_fname, be.bstrerror());
1395 return bsub_exit_nok;
1402 return bsub_exit_ok;
1404 #endif /* HAVE_EXTENDED_ACL */
1407 #endif /* HAVE_ACL */
1409 static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1411 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1412 int used_bytes, total_bytes, cnt;
1413 char *bp, *target_attrname, *attribs;
1414 char *linked_target = NULL;
1415 char *acl_text = NULL;
1419 struct timeval times[2];
1420 bsub_exit_code retval = bsub_exit_nok;
1423 * Parse the xattr stream. First the part that is the same for all xattrs.
1426 total_bytes = jcr->xattr_data_len;
1429 * The name of the target xattr has a leading / we are not interested
1430 * in that so skip it when decoding the string. We always start a the /
1431 * of the xattr space anyway.
1433 target_attrname = jcr->xattr_data + 1;
1434 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1435 (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1441 * Open the file on which to restore the xattrs read-only.
1443 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1445 Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1446 jcr->last_fname, be.bstrerror());
1447 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1448 jcr->last_fname, be.bstrerror());
1453 * Open the xattr naming space and make it the current working dir.
1455 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1457 Jmsg2(jcr, M_ERROR, 0, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1458 jcr->last_fname, be.bstrerror());
1459 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1460 jcr->last_fname, be.bstrerror());
1464 if (fchdir(attrdirfd) < 0) {
1466 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1467 jcr->last_fname, be.bstrerror());
1468 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1469 jcr->last_fname, attrdirfd, be.bstrerror());
1474 * Try to open the correct xattr subdir based on the target_attrname given.
1475 * e.g. check if its a subdir attrname. Each / in the string makes us go
1478 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1481 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1483 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1484 target_attrname, jcr->last_fname, be.bstrerror());
1485 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1486 target_attrname, jcr->last_fname, be.bstrerror());
1494 * Open the xattr naming space.
1496 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1498 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1499 target_attrname, jcr->last_fname, be.bstrerror());
1500 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1501 target_attrname, jcr->last_fname, be.bstrerror());
1509 * Make the xattr space our current workingdir.
1511 if (fchdir(attrdirfd) < 0) {
1513 Jmsg3(jcr, M_ERROR, 0, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1514 target_attrname, jcr->last_fname, be.bstrerror());
1515 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1516 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1520 target_attrname = ++bp;
1524 * Decode the attributes from the stream.
1526 decode_stat(attribs, &st, &inum);
1529 * Decode the next field (acl_text).
1531 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1532 (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1538 * Based on the filetype perform the correct action. We support most filetypes here, more
1539 * then the actual implementation on Solaris supports so some code may never get executed
1540 * due to limitations in the implementation.
1542 switch (st.st_mode & S_IFMT) {
1545 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1547 unlinkat(attrdirfd, target_attrname, 0);
1548 if (mkfifo(target_attrname, st.st_mode) < 0) {
1550 Jmsg3(jcr, M_ERROR, 0, _("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) {
1565 Jmsg3(jcr, M_ERROR, 0, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1566 target_attrname, jcr->last_fname, be.bstrerror());
1567 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1568 target_attrname, jcr->last_fname, be.bstrerror());
1574 * If its not the hidden_dir create the entry.
1575 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1577 if (strcmp(target_attrname, ".")) {
1578 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1579 if (mkdir(target_attrname, st.st_mode) < 0) {
1581 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1582 target_attrname, jcr->last_fname, be.bstrerror());
1583 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1584 target_attrname, jcr->last_fname, be.bstrerror());
1591 * See if this is a hard linked file. e.g. inum != 0
1596 unlinkat(attrdirfd, target_attrname, 0);
1597 if (link(linked_target, target_attrname) < 0) {
1599 Jmsg4(jcr, M_ERROR, 0, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1600 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1601 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1602 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1607 * Successfully restored xattr.
1609 retval = bsub_exit_ok;
1612 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1613 (used_bytes = (bp - jcr->xattr_data)) >= total_bytes) {
1617 if (used_bytes < (total_bytes - 1))
1621 * Restore the actual xattr.
1623 if (!is_extensible) {
1624 unlinkat(attrdirfd, target_attrname, 0);
1627 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1629 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1630 target_attrname, jcr->last_fname, be.bstrerror());
1631 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1632 target_attrname, jcr->last_fname, be.bstrerror());
1638 * Restore the actual data.
1640 if (st.st_size > 0) {
1641 used_bytes = (data - jcr->xattr_data);
1642 cnt = total_bytes - used_bytes;
1645 * Do a sanity check, the st.st_size should be the same as the number of bytes
1646 * we have available as data of the stream.
1648 if (cnt != st.st_size) {
1649 Jmsg2(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
1650 target_attrname, jcr->last_fname);
1651 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1652 target_attrname, jcr->last_fname);
1657 cnt = write(attrfd, data, cnt);
1660 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
1661 target_attrname, jcr->last_fname, be.bstrerror());
1662 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
1663 target_attrname, jcr->last_fname, be.bstrerror());
1669 cnt = total_bytes - used_bytes;
1675 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1679 if (symlink(linked_target, target_attrname) < 0) {
1681 Jmsg4(jcr, M_ERROR, 0, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
1682 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1683 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
1684 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1689 * Successfully restored xattr.
1691 retval = bsub_exit_ok;
1698 * Restore owner and acl for non extensible attributes.
1700 if (!is_extensible) {
1701 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
1705 * Gentile way of the system saying this type of xattr layering is not supported.
1706 * But as this is not an error we return a positive return value.
1708 retval = bsub_exit_ok;
1712 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1713 target_attrname, jcr->last_fname, be.bstrerror());
1714 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1715 target_attrname, jcr->last_fname, be.bstrerror());
1722 if (acl_text && *acl_text)
1723 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bsub_exit_ok)
1725 #endif /* HAVE_ACL */
1728 * For a non extensible attribute restore access and modification time on the xattr.
1730 if (!is_extensible) {
1731 times[0].tv_sec = st.st_atime;
1732 times[0].tv_usec = 0;
1733 times[1].tv_sec = st.st_mtime;
1734 times[1].tv_usec = 0;
1736 if (futimesat(attrdirfd, target_attrname, times) < 0) {
1738 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
1739 target_attrname, jcr->last_fname, be.bstrerror());
1740 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
1741 target_attrname, jcr->last_fname, be.bstrerror());
1747 * Successfully restored xattr.
1749 retval = bsub_exit_ok;
1753 Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
1755 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
1762 if (attrdirfd != -1) {
1771 static bsub_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt, int default_stream)
1774 bsub_exit_code retval = bsub_exit_ok;
1777 * First see if extended attributes or extensible attributes are present.
1778 * If not just pretend things went ok.
1780 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1784 * As we change the cwd in the save function save the current cwd
1785 * for restore after return from the solaris_save_xattrs function.
1787 xattr_link_cache = New(alist(10, not_owned_by_alist));
1788 getcwd(cwd, sizeof(cwd));
1789 retval = solaris_save_xattrs(jcr, NULL, NULL);
1791 delete xattr_link_cache;
1792 xattr_link_cache = NULL;
1797 static bsub_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
1800 bool is_extensible = false;
1801 bsub_exit_code retval;
1804 * First make sure we can restore xattr on the filesystem.
1807 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1808 case STREAM_XATTR_SOLARIS_SYS:
1809 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1810 Qmsg1(jcr, M_WARNING, 0,
1811 _("Failed to restore extensible attributes on file \"%s\"\n"),
1813 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1815 return bsub_exit_nok;
1818 is_extensible = true;
1821 case STREAM_XATTR_SOLARIS:
1822 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1823 Qmsg1(jcr, M_WARNING, 0,
1824 _("Failed to restore extended attributes on file \"%s\"\n"),
1826 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1828 return bsub_exit_nok;
1832 return bsub_exit_nok;
1836 * As we change the cwd in the restore function save the current cwd
1837 * for restore after return from the solaris_restore_xattrs function.
1839 getcwd(cwd, sizeof(cwd));
1840 retval = solaris_restore_xattrs(jcr, is_extensible);
1847 * Function pointers to the build and parse function to use for these xattrs.
1849 static bsub_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt, int default_stream) = solaris_build_xattr_streams;
1850 static bsub_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
1853 * Number of xattr streams this OS supports and an array with integers with the actual stream numbers.
1855 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1856 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
1858 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
1859 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
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;