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 bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
59 bool parse_xattr_stream(JCR *jcr, int stream)
65 * Send a XATTR stream to the SD.
67 static bool 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"),
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"),
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"),
112 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
118 * This is a supported OS, See what kind of interface we should use.
119 * Start with the generic interface used by most OS-es.
121 #if defined(HAVE_DARWIN_OS) \
122 || defined(HAVE_FREEBSD_OS) \
123 || defined(HAVE_LINUX_OS) \
124 || defined(HAVE_NETBSD_OS)
126 #ifdef HAVE_SYS_XATTR_H
127 #include <sys/xattr.h>
131 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
132 * listxattr, getxattr and setxattr with an extra options argument
133 * which mimics the l variants of the functions when we specify
134 * XATTR_NOFOLLOW as the options value.
136 #if defined(HAVE_DARWIN_OS)
137 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
138 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
139 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
142 * Fallback to the non l-functions when those are not available.
144 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
145 #define lgetxattr getxattr
147 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
148 #define lsetxattr setxattr
150 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
151 #define llistxattr listxattr
155 static void xattr_drop_internal_table(xattr_t *xattr_value_list)
157 xattr_t *current_xattr;
160 * Walk the list of xattrs and free allocated memory on traversing.
162 for (current_xattr = xattr_value_list;
163 current_xattr != (xattr_t *)NULL;
166 * See if we can shortcut.
168 if (current_xattr->magic != XATTR_MAGIC)
171 free(current_xattr->name);
173 if (current_xattr->value_length > 0)
174 free(current_xattr->value);
178 * Free the array of control structs.
180 free(xattr_value_list);
184 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
185 * which encodes one or more xattr_t structures.
187 * The Serialized stream consists of the following elements:
188 * magic - A magic string which makes it easy to detect any binary incompatabilites
189 * name_length - The length of the following xattr name
190 * name - The name of the extended attribute
191 * value_length - The length of the following xattr data
192 * value - The actual content of the extended attribute
194 * This is repeated 1 or more times.
197 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list)
199 xattr_t *current_xattr;
203 * Make sure the serialized stream fits in the poolmem buffer.
204 * We allocate some more to be sure the stream is gonna fit.
206 jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, expected_serialize_len + 10);
207 ser_begin(jcr->xattr_data, expected_serialize_len + 10);
210 * Walk the list of xattrs and serialize the data.
212 for (current_xattr = xattr_value_list; current_xattr != (xattr_t *)NULL; current_xattr++) {
214 * See if we can shortcut.
216 if (current_xattr->magic != XATTR_MAGIC)
219 ser_uint32(current_xattr->magic);
220 ser_uint32(current_xattr->name_length);
221 ser_bytes(current_xattr->name, current_xattr->name_length);
223 ser_uint32(current_xattr->value_length);
224 ser_bytes(current_xattr->value, current_xattr->value_length);
227 ser_end(jcr->xattr_data, expected_serialize_len + 10);
228 jcr->xattr_data_len = ser_length(jcr->xattr_data);
230 return jcr->xattr_data_len;
233 static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
236 int32_t xattr_list_len,
238 uint32_t expected_serialize_len = 0;
239 char *xattr_list, *bp;
240 xattr_t *xattr_value_list, *current_xattr;
243 * First get the length of the available list with extended attributes.
245 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
246 if (xattr_list_len < 0) {
248 Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
249 jcr->last_fname, be.bstrerror());
250 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
251 jcr->last_fname, be.bstrerror());
252 return true; /* non-fatal return */
253 } else if (xattr_list_len == 0) {
258 * Allocate room for the extented attribute list.
260 xattr_list = (char *)malloc(xattr_list_len + 1);
261 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
264 * Get the actual list of extended attributes names for a file.
266 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
267 if (xattr_list_len < 0) {
269 Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
270 jcr->last_fname, be.bstrerror());
271 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
272 jcr->last_fname, be.bstrerror());
274 return true; /* non-fatal return */
276 xattr_list[xattr_list_len] = '\0';
279 * Count the number of extended attributes on a file.
282 while ((bp - xattr_list) + 1 < xattr_list_len) {
283 #if defined(HAVE_LINUX_OS)
285 * On Linux you also get the acls in the extented attribute list.
286 * So we check if we are already backing up acls and if we do we
287 * don't store the extended attribute with the same info.
289 if ((ff_pkt->flags & FO_ACL) == 0 || strcmp(bp, "system.posix_acl_access"))
295 bp = strchr(bp, '\0') + 1;
305 * Allocate enough room to hold all extended attributes.
306 * After allocating the storage make sure its empty by zeroing it.
308 xattr_value_list = (xattr_t *)malloc(count * sizeof(xattr_t));
309 memset((caddr_t)xattr_value_list, 0, count * sizeof(xattr_t));
312 * Walk the list of extended attributes names and retrieve the data.
313 * We already count the bytes needed for serializing the stream later on.
315 current_xattr = xattr_value_list;
317 while ((bp - xattr_list) + 1 < xattr_list_len) {
318 #if defined(HAVE_LINUX_OS)
319 if (ff_pkt->flags & FO_ACL && !strcmp(bp, "system.posix_acl_access")) {
320 bp = strchr(bp, '\0') + 1;
326 * Each xattr valuepair starts with a magic so we can parse it easier.
328 current_xattr->magic = XATTR_MAGIC;
329 expected_serialize_len += sizeof(current_xattr->magic);
332 * Allocate space for storing the name.
334 current_xattr->name_length = strlen(bp);
335 current_xattr->name = (char *)malloc(current_xattr->name_length);
336 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
338 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
341 * First see how long the value is for the extended attribute.
343 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
344 if (xattr_value_len < 0) {
346 Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
347 jcr->last_fname, be.bstrerror());
348 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
349 jcr->last_fname, be.bstrerror());
354 * Allocate space for storing the value.
356 current_xattr->value = (char *)malloc(xattr_value_len);
357 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
359 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
360 if (xattr_value_len < 0) {
362 Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
363 jcr->last_fname, be.bstrerror());
364 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
365 jcr->last_fname, be.bstrerror());
370 * Store the actual length of the value.
372 current_xattr->value_length = xattr_value_len;
373 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
376 * Protect ourself against things getting out of hand.
378 if (expected_serialize_len >= MAX_XATTR_STREAM) {
379 Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
380 jcr->last_fname, MAX_XATTR_STREAM);
388 bp = strchr(bp, '\0') + 1;
392 * Serialize the datastream.
394 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
395 Jmsg1(jcr, M_ERROR, 0, _("Failed to serialize extended attributes on file \"%s\"\n"),
397 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
402 xattr_drop_internal_table(xattr_value_list);
406 * Send the datastream to the SD.
408 return send_xattr_stream(jcr, stream);
411 xattr_drop_internal_table(xattr_value_list);
413 return true; /* non-fatal return */
416 static bool generic_xattr_parse_streams(JCR *jcr)
419 xattr_t current_xattr;
420 bool retval = true; /* default non-fatal */
423 * Parse the stream and perform the setxattr calls on the file.
425 * Start unserializing the data. We keep on looping while we have not
426 * unserialized all bytes in the stream.
428 unser_begin(jcr->xattr_data, jcr->xattr_data_len);
429 while (unser_length(jcr->xattr_data) < jcr->xattr_data_len) {
431 * First make sure the magic is present. This way we can easily catch corruption.
432 * Any missing MAGIC is fatal we do NOT try to continue.
434 unser_uint32(current_xattr.magic);
435 if (current_xattr.magic != XATTR_MAGIC) {
436 Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
438 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
440 return true; /* non-fatal return */
444 * Decode the valuepair. First decode the length of the name.
446 unser_uint32(current_xattr.name_length);
449 * Allocate room for the name and decode its content.
451 current_xattr.name = (char *)malloc(current_xattr.name_length + 1);
452 unser_bytes(current_xattr.name, current_xattr.name_length);
455 * The xattr_name needs to be null terminated for lsetxattr.
457 current_xattr.name[current_xattr.name_length] = '\0';
460 * Decode the value length.
462 unser_uint32(current_xattr.value_length);
465 * Allocate room for the value and decode its content.
467 current_xattr.value = (char *)malloc(current_xattr.value_length);
468 unser_bytes(current_xattr.value, current_xattr.value_length);
471 * Try to set the extended attribute on the file.
472 * If we fail to set this attribute we flag the error but its not fatal,
473 * we try to restore the other extended attributes too.
475 if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
476 current_xattr.value_length, 0) != 0) {
478 Jmsg2(jcr, M_ERROR, 0, _("lsetxattr error on file \"%s\": ERR=%s\n"),
479 jcr->last_fname, be.bstrerror());
480 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
481 jcr->last_fname, be.bstrerror());
485 * Free the temporary buffers.
487 free(current_xattr.name);
488 free(current_xattr.value);
491 unser_end(jcr->xattr_data, jcr->xattr_data_len);
495 #if defined(HAVE_DARWIN_OS)
496 static bool darwin_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
498 return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_DARWIN);
501 static bool darwin_parse_xattr_stream(JCR *jcr, int stream)
504 case STREAM_XATTR_DARWIN:
505 return generic_xattr_parse_streams(jcr);
507 Jmsg2(jcr, M_WARNING, 0,
508 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
509 jcr->last_fname, stream);
510 return true; /* non-fatal error */
513 #elif defined(HAVE_FREEBSD_OS)
514 static bool freebsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
516 return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_FREEBSD);
519 static bool freebsd_parse_xattr_stream(JCR *jcr, int stream)
522 case STREAM_XATTR_FREEBSD:
523 return generic_xattr_parse_streams(jcr);
525 Jmsg2(jcr, M_WARNING, 0,
526 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
527 jcr->last_fname, stream);
528 return true; /* non-fatal error */
531 #elif defined(HAVE_LINUX_OS)
532 static bool linux_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
534 return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_LINUX);
537 static bool linux_parse_xattr_stream(JCR *jcr, int stream)
540 case STREAM_XATTR_LINUX:
541 return generic_xattr_parse_streams(jcr);
543 Jmsg2(jcr, M_WARNING, 0,
544 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
545 jcr->last_fname, stream);
546 return true; /* non-fatal error */
549 #elif defined(HAVE_NETBSD_OS)
550 static bool netbsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
552 return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_NETBSD);
555 static bool netbsd_parse_xattr_stream(JCR *jcr, int stream)
558 case STREAM_XATTR_NETBSD:
559 return generic_xattr_parse_streams(jcr);
561 Jmsg2(jcr, M_WARNING, 0,
562 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
563 jcr->last_fname, stream);
564 return true; /* non-fatal error */
568 #elif defined(HAVE_SUN_OS)
570 * Solaris extended attributes were introduced in Solaris 9
573 * Solaris extensible attributes were introduced in OpenSolaris
574 * by PSARC 2007/315 Solaris extensible attributes are also
575 * sometimes called extended system attributes.
577 * man fsattr(5) on Solaris gives a wealth of info. The most
578 * important bits are:
580 * Attributes are logically supported as files within the file
581 * system. The file system is therefore augmented with an
582 * orthogonal name space of file attributes. Any file (includ-
583 * ing attribute files) can have an arbitrarily deep attribute
584 * tree associated with it. Attribute values are accessed by
585 * file descriptors obtained through a special attribute inter-
586 * face. This logical view of "attributes as files" allows the
587 * leveraging of existing file system interface functionality
588 * to support the construction, deletion, and manipulation of
591 * The special files "." and ".." retain their accustomed
592 * semantics within the attribute hierarchy. The "." attribute
593 * file refers to the current directory and the ".." attribute
594 * file refers to the parent directory. The unnamed directory
595 * at the head of each attribute tree is considered the "child"
596 * of the file it is associated with and the ".." file refers
597 * to the associated file. For any non-directory file with
598 * attributes, the ".." entry in the unnamed directory refers
599 * to a file that is not a directory.
601 * Conceptually, the attribute model is fully general. Extended
602 * attributes can be any type of file (doors, links, direc-
603 * tories, and so forth) and can even have their own attributes
604 * (fully recursive). As a result, the attributes associated
605 * with a file could be an arbitrarily deep directory hierarchy
606 * where each attribute could have an equally complex attribute
607 * tree associated with it. Not all implementations are able
608 * to, or want to, support the full model. Implementation are
609 * therefore permitted to reject operations that are not sup-
610 * ported. For example, the implementation for the UFS file
611 * system allows only regular files as attributes (for example,
612 * no sub-directories) and rejects attempts to place attributes
615 * The following list details the operations that are rejected
616 * in the current implementation:
618 * link Any attempt to create links between
619 * attribute and non-attribute space
620 * is rejected to prevent security-
621 * related or otherwise sensitive
622 * attributes from being exposed, and
623 * therefore manipulable, as regular
626 * rename Any attempt to rename between
627 * attribute and non-attribute space
628 * is rejected to prevent an already
629 * linked file from being renamed and
630 * thereby circumventing the link res-
633 * mkdir, symlink, mknod Any attempt to create a "non-
634 * regular" file in attribute space is
635 * rejected to reduce the functional-
636 * ity, and therefore exposure and
637 * risk, of the initial implementa-
640 * The entire available name space has been allocated to "gen-
641 * eral use" to bring the implementation in line with the NFSv4
642 * draft standard [NFSv4]. That standard defines "named attri-
643 * butes" (equivalent to Solaris Extended Attributes) with no
644 * naming restrictions. All Sun applications making use of
645 * opaque extended attributes will use the prefix "SUNW".
648 #ifdef HAVE_SYS_ATTR_H
649 #include <sys/attr.h>
656 #ifdef HAVE_SYS_NVPAIR_H
657 #include <sys/nvpair.h>
660 #ifdef HAVE_SYS_ACL_H
665 * This is the count of xattrs saved on a certain file, it gets reset
666 * on each new file processed and is used to see if we need to send
667 * the hidden xattr dir data. We only send that data when we encounter
668 * an other xattr on the file.
670 static int nr_xattr_saved = 0;
671 static char toplevel_hidden_dir_xattr_data[MAXSTRING];
672 static int toplevel_hidden_dir_xattr_data_len;
675 * This code creates a temporary cache with entries for each xattr which has
676 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
678 static xattr_link_cache_entry_t *xattr_link_cache_head = NULL,
679 *xattr_link_cache_tail = NULL;
681 static struct xattr_link_cache_entry *find_xattr_link_cache_entry(ino_t inum)
683 xattr_link_cache_entry_t *ptr;
685 for (ptr = xattr_link_cache_head; ptr != NULL; ptr = ptr->next) {
686 if (ptr->inum == inum) {
693 static void add_xattr_link_cache_entry(ino_t inum, char *target)
695 xattr_link_cache_entry_t *ptr;
697 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(struct xattr_link_cache_entry));
698 memset((caddr_t)ptr, 0, sizeof(struct xattr_link_cache_entry));
700 strncpy(ptr->target, target, sizeof(ptr->target));
701 if (xattr_link_cache_head == NULL) {
702 xattr_link_cache_head = ptr;
704 if (xattr_link_cache_tail != NULL) {
705 xattr_link_cache_tail->next = ptr;
709 static void drop_xattr_link_cache(void)
711 xattr_link_cache_entry_t *ptr, *next;
713 for (ptr = xattr_link_cache_tail; ptr != NULL; ptr = next) {
717 xattr_link_cache_head = NULL;
718 xattr_link_cache_tail = NULL;
721 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
723 * This function returns true if a non default extended system attribute
724 * list is associated with fd and returns false when an error has occured
725 * or when only extended system attributes other than archive,
726 * av_modified or crtime are set.
728 * The function returns true for the following cases:
730 * - any extended system attribute other than the default attributes
731 * ('archive', 'av_modified' and 'crtime') is set
732 * - nvlist has NULL name string
733 * - nvpair has data type of 'nvlist'
734 * - default data type.
736 static bool solaris_has_non_transient_extensible_attributes(int fd)
746 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
751 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
752 name = nvpair_name(pair);
755 fattr = name_to_attr(name);
761 type = nvpair_type(pair);
763 case DATA_TYPE_BOOLEAN_VALUE:
764 if (nvpair_value_boolean_value(pair, &value) != 0) {
767 if (value && fattr != F_ARCHIVE &&
768 fattr != F_AV_MODIFIED) {
773 case DATA_TYPE_UINT64_ARRAY:
774 if (fattr != F_CRTIME) {
779 case DATA_TYPE_NVLIST:
787 if (response != NULL) {
788 nvlist_free(response);
792 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
794 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
796 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
797 * There is no need to store those acls as we already store the stat bits too.
799 static bool acl_is_trivial(int count, aclent_t *entries)
804 for (n = 0; n < count; n++) {
806 if (!(ace->a_type == USER_OBJ ||
807 ace->a_type == GROUP_OBJ ||
808 ace->a_type == OTHER_OBJ ||
809 ace->a_type == CLASS_OBJ))
814 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
816 static bool solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
819 #ifdef HAVE_EXTENDED_ACL
824 * See if this attribute has an ACL
826 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
827 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
829 * See if there is a non trivial acl on the file.
831 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
832 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
834 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
835 attrname, jcr->last_fname, be.bstrerror());
836 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
837 attrname, jcr->last_fname, be.bstrerror());
838 return true; /* non-fatal */
842 #if defined(ACL_SID_FMT)
844 * New format flag added in newer Solaris versions.
846 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
848 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
849 #endif /* ACL_SID_FMT */
851 *acl_text = acl_totext(aclp, flags);
861 #else /* HAVE_EXTENDED_ACL */
863 aclent_t *acls = NULL;
866 * See if this attribute has an ACL
869 n = facl(fd, GETACLCNT, 0, NULL);
871 n = acl(attrname, GETACLCNT, 0, NULL);
874 if (n >= MIN_ACL_ENTRIES) {
875 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
876 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
877 acl(attrname, GETACL, n, acls) != n) {
879 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
880 attrname, jcr->last_fname, be.bstrerror());
881 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
882 attrname, jcr->last_fname, be.bstrerror());
884 return true; /* non-fatal */
888 * See if there is a non trivial acl on the file.
890 if (!acl_is_trivial(n, acls)) {
891 if ((*acl_text = acltotext(acls, n)) == NULL) {
893 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
894 attrname, jcr->last_fname, be.bstrerror());
895 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
896 attrname, jcr->last_fname, be.bstrerror());
898 return true; /* non-fatal */
910 #endif /* HAVE_EXTENDED_ACL */
913 return false; /* fatal return */
914 #endif /* HAVE_ACL */
918 * Forward declaration for recursive function call.
920 static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
923 * Save an extended or extensible attribute.
924 * This is stored as an opaque stream of bytes with the following encoding:
926 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
928 * or for a hardlinked or symlinked attribute
930 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
932 * xattr_name can be a subpath relative to the file the xattr is on.
933 * stat_buffer is the string representation of the stat struct.
934 * acl_string is an acl text when a non trivial acl is set on the xattr.
935 * actual_xattr_data is the content of the xattr file.
937 static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
938 const char *attrname, bool toplevel_hidden_dir, int stream)
943 struct xattr_link_cache_entry *xlce;
944 char target_attrname[PATH_MAX];
945 char link_source[PATH_MAX];
946 char *acl_text = NULL;
947 char attribs[MAXSTRING];
949 bool retval = true; /* default is non-fatal */
951 snprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
954 * Get the stats of the extended or extensible attribute.
956 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
958 Jmsg3(jcr, M_ERROR, 0, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
959 target_attrname, jcr->last_fname, be.bstrerror());
960 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
961 target_attrname, jcr->last_fname, be.bstrerror());
966 * Based on the filetype perform the correct action. We support most filetypes here, more
967 * then the actual implementation on Solaris supports so some code may never get executed
968 * due to limitations in the implementation.
970 switch (st.st_mode & S_IFMT) {
975 * Get any acl on the xattr.
977 if (!solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text))
981 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
982 * Encode the stat struct into an ASCII representation.
984 encode_stat(attribs, &st, 0, stream);
985 cnt = snprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
986 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
991 * Get any acl on the xattr.
993 if (!solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text))
997 * See if this is the toplevel_hidden_dir being saved.
999 if (toplevel_hidden_dir) {
1001 * Save the data for later storage when we encounter a real xattr.
1002 * Encode the stat struct into an ASCII representation and jump out of the function.
1004 encode_stat(attribs, &st, 0, stream);
1005 toplevel_hidden_dir_xattr_data_len = snprintf(toplevel_hidden_dir_xattr_data,
1006 sizeof(toplevel_hidden_dir_xattr_data),
1008 target_attrname, 0, attribs, 0,
1009 (acl_text) ? acl_text : "", 0);
1013 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1014 * Encode the stat struct into an ASCII representation.
1016 encode_stat(attribs, &st, 0, stream);
1017 cnt = snprintf(buffer, sizeof(buffer),
1019 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1024 * If this is a hardlinked file check the inode cache for a hit.
1026 if (st.st_nlink > 1) {
1028 * See if the cache already knows this inode number.
1030 if ((xlce = find_xattr_link_cache_entry(st.st_ino)) != NULL) {
1032 * Generate a xattr encoding with the reference to the target in there.
1034 encode_stat(attribs, &st, st.st_ino, stream);
1035 cnt = snprintf(buffer, sizeof(buffer),
1037 target_attrname, 0, attribs, 0, xlce->target, 0);
1038 pm_memcpy(jcr->xattr_data, buffer, cnt);
1039 jcr->xattr_data_len = cnt;
1040 retval = send_xattr_stream(jcr, stream);
1043 * For a hard linked file we are ready now, no need to recursively save the attributes.
1049 * Store this hard linked file in the cache.
1050 * Store the name relative to the top level xattr space.
1052 add_xattr_link_cache_entry(st.st_ino, target_attrname + 1);
1056 * Get any acl on the xattr.
1058 if (!solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text)) {
1063 * Encode the stat struct into an ASCII representation.
1065 encode_stat(attribs, &st, 0, stream);
1066 cnt = snprintf(buffer, sizeof(buffer),
1068 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1071 * Open the extended or extensible attribute file.
1073 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1075 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1076 target_attrname, jcr->last_fname, be.bstrerror());
1077 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1078 target_attrname, jcr->last_fname, be.bstrerror());
1085 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1086 * Encode the stat struct into an ASCII representation.
1088 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1090 Jmsg3(jcr, M_ERROR, 0, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1091 target_attrname, jcr->last_fname, be.bstrerror());
1092 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1093 target_attrname, jcr->last_fname, be.bstrerror());
1098 * Generate a xattr encoding with the reference to the target in there.
1100 encode_stat(attribs, &st, st.st_ino, stream);
1101 cnt = snprintf(buffer, sizeof(buffer),
1103 target_attrname, 0, attribs, 0, link_source, 0);
1104 pm_memcpy(jcr->xattr_data, buffer, cnt);
1105 jcr->xattr_data_len = cnt;
1106 retval = send_xattr_stream(jcr, stream);
1109 * For a soft linked file we are ready now, no need to recursively save the attributes.
1118 * See if this is the first real xattr being saved. If it is save the toplevel_hidden_dir attributes first.
1120 if (nr_xattr_saved == 0) {
1121 pm_memcpy(jcr->xattr_data, toplevel_hidden_dir_xattr_data, toplevel_hidden_dir_xattr_data_len);
1122 jcr->xattr_data_len = toplevel_hidden_dir_xattr_data_len;
1123 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1126 pm_memcpy(jcr->xattr_data, buffer, cnt);
1127 jcr->xattr_data_len = cnt;
1130 * Only dump the content of regular files.
1132 switch (st.st_mode & S_IFMT) {
1134 if (st.st_size > 0) {
1136 * Protect ourself against things getting out of hand.
1138 if (st.st_size >= MAX_XATTR_STREAM) {
1139 Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1140 jcr->last_fname, MAX_XATTR_STREAM);
1144 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1145 jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, jcr->xattr_data_len + cnt);
1146 memcpy(jcr->xattr_data + jcr->xattr_data_len, buffer, cnt);
1147 jcr->xattr_data_len += cnt;
1151 Jmsg2(jcr, M_ERROR, 0, _("Unable to read content of xattr %s on file \"%s\"\n"),
1152 target_attrname, jcr->last_fname);
1153 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1154 target_attrname, jcr->last_fname);
1165 retval = send_xattr_stream(jcr, stream);
1170 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1171 * available on this extended attribute.
1174 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1177 * The recursive call could change our working dir so change back to the wanted workdir.
1179 if (fchdir(fd) < 0) {
1181 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1182 jcr->last_fname, be.bstrerror());
1183 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1184 jcr->last_fname, fd, be.bstrerror());
1199 static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1202 int fd, filefd = -1, attrdirfd = -1;
1205 char current_xattr_namespace[PATH_MAX];
1206 bool retval = true; /* default non-fatal error */
1209 * Determine what argument to use. Use attr_parent when set
1210 * (recursive call) or jcr->last_fname for first call. Also save
1211 * the current depth of the xattr_space we are in.
1215 if (xattr_namespace) {
1216 snprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1217 xattr_namespace, attr_parent);
1219 strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1222 name = jcr->last_fname;
1223 strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1227 * Open the file on which to save the xattrs read-only.
1229 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1231 Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1232 jcr->last_fname, be.bstrerror());
1233 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1234 jcr->last_fname, be.bstrerror());
1239 * Open the xattr naming space.
1241 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1245 * Gentile way of the system saying this type of xattr layering is not supported.
1246 * Which is not problem we just forget about this this xattr.
1247 * But as this is not an error we return a positive return value.
1253 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1254 name, jcr->last_fname, be.bstrerror());
1255 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1256 name, jcr->last_fname, be.bstrerror());
1262 * We need to change into the attribute directory to determine if each of the
1263 * attributes should be saved.
1265 if (fchdir(attrdirfd) < 0) {
1267 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1268 jcr->last_fname, be.bstrerror());
1269 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1270 jcr->last_fname, attrdirfd, be.bstrerror());
1275 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1276 * else because the readdir returns "." entry after the extensible attr entry.
1277 * And as we want this entry before anything else we better just save its data.
1280 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1281 true, STREAM_XATTR_SOLARIS);
1283 if ((fd = dup(attrdirfd)) == -1 ||
1284 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1286 Jmsg2(jcr, M_ERROR, 0, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1287 jcr->last_fname, be.bstrerror());
1288 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1289 jcr->last_fname, fd, be.bstrerror());
1295 * Walk the namespace.
1297 while (dp = readdir(dirp)) {
1299 * Skip only the toplevel . dir.
1301 if (!attr_parent && !strcmp(dp->d_name, "."))
1305 * Skip all .. directories
1307 if (!strcmp(dp->d_name, ".."))
1310 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1311 current_xattr_namespace, dp->d_name, jcr->last_fname);
1313 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1315 * We are not interested in read-only extensible attributes.
1317 if (!strcmp(dp->d_name, VIEW_READONLY)) {
1318 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1319 current_xattr_namespace, dp->d_name, jcr->last_fname);
1325 * We are only interested in read-write extensible attributes
1326 * when they contain non-transient values.
1328 if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1330 * Determine if there are non-transient system attributes at the toplevel.
1331 * We need to provide a fd to the open file.
1333 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1334 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1335 current_xattr_namespace, dp->d_name, jcr->last_fname);
1342 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1343 false, STREAM_XATTR_SOLARIS_SYS);
1346 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1351 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1352 false, STREAM_XATTR_SOLARIS);
1359 if (attrdirfd != -1)
1367 static bool solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1369 #ifdef HAVE_EXTENDED_ACL
1373 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1374 Jmsg1(jcr, M_ERROR, 0, _("Unable to convert acl from text on file \"%s\"\n"),
1376 return true; /* non-fatal */
1379 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1380 acl_set(attrname, aclp) != 0) {
1382 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1383 attrname, jcr->last_fname, be.bstrerror());
1384 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1385 attrname, jcr->last_fname, be.bstrerror());
1386 return true; /* non-fatal */
1394 #else /* HAVE_EXTENDED_ACL */
1396 aclent_t *acls = NULL;
1398 acls = aclfromtext(acl_text, &n);
1400 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1401 acl(attrname, SETACL, n, acls) != 0) {
1403 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1404 attrname, jcr->last_fname, be.bstrerror());
1405 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1406 attrname, jcr->last_fname, be.bstrerror());
1407 return true; /* non-fatal */
1416 #endif /* HAVE_EXTENDED_ACL */
1419 #endif /* HAVE_ACL */
1421 static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1423 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1424 int used_bytes, total_bytes, cnt;
1425 char *bp, *target_attrname, *attribs;
1426 char *linked_target = NULL;
1427 char *acl_text = NULL;
1431 struct timeval times[2];
1432 bool retval = true; /* default non-fatal */
1435 * Parse the xattr stream. First the part that is the same for all xattrs.
1438 total_bytes = jcr->xattr_data_len;
1441 * The name of the target xattr has a leading / we are not interested
1442 * in that so skip it when decoding the string. We always start a the /
1443 * of the xattr space anyway.
1445 target_attrname = jcr->xattr_data + 1;
1446 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1447 (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1453 * Open the file on which to restore the xattrs read-only.
1455 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1457 Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1458 jcr->last_fname, be.bstrerror());
1459 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1460 jcr->last_fname, be.bstrerror());
1465 * Open the xattr naming space and make it the current working dir.
1467 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1469 Jmsg2(jcr, M_ERROR, 0, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1470 jcr->last_fname, be.bstrerror());
1471 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1472 jcr->last_fname, be.bstrerror());
1476 if (fchdir(attrdirfd) < 0) {
1478 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1479 jcr->last_fname, be.bstrerror());
1480 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1481 jcr->last_fname, attrdirfd, be.bstrerror());
1486 * Try to open the correct xattr subdir based on the target_attrname given.
1487 * e.g. check if its a subdir attrname. Each / in the string makes us go
1490 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1493 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1495 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1496 target_attrname, jcr->last_fname, be.bstrerror());
1497 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1498 target_attrname, jcr->last_fname, be.bstrerror());
1506 * Open the xattr naming space.
1508 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1510 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1511 target_attrname, jcr->last_fname, be.bstrerror());
1512 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1513 target_attrname, jcr->last_fname, be.bstrerror());
1521 * Make the xattr space our current workingdir.
1523 if (fchdir(attrdirfd) < 0) {
1525 Jmsg3(jcr, M_ERROR, 0, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1526 target_attrname, jcr->last_fname, be.bstrerror());
1527 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1528 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1532 target_attrname = ++bp;
1536 * Decode the attributes from the stream.
1538 decode_stat(attribs, &st, &inum);
1541 * Decode the next field (acl_text).
1543 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1544 (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1550 * Based on the filetype perform the correct action. We support most filetypes here, more
1551 * then the actual implementation on Solaris supports so some code may never get executed
1552 * due to limitations in the implementation.
1554 switch (st.st_mode & S_IFMT) {
1557 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1559 unlinkat(attrdirfd, target_attrname, 0);
1560 if (mkfifo(target_attrname, st.st_mode) < 0) {
1562 Jmsg3(jcr, M_ERROR, 0, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1563 target_attrname, jcr->last_fname, be.bstrerror());
1564 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1565 target_attrname, jcr->last_fname, be.bstrerror());
1572 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1574 unlinkat(attrdirfd, target_attrname, 0);
1575 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1577 Jmsg3(jcr, M_ERROR, 0, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1578 target_attrname, jcr->last_fname, be.bstrerror());
1579 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1580 target_attrname, jcr->last_fname, be.bstrerror());
1586 * If its not the hidden_dir create the entry.
1587 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1589 if (strcmp(target_attrname, ".")) {
1590 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1591 if (mkdir(target_attrname, st.st_mode) < 0) {
1593 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1594 target_attrname, jcr->last_fname, be.bstrerror());
1595 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1596 target_attrname, jcr->last_fname, be.bstrerror());
1603 * See if this is a hard linked file. e.g. inum != 0
1608 unlinkat(attrdirfd, target_attrname, 0);
1609 if (link(linked_target, target_attrname) < 0) {
1611 Jmsg4(jcr, M_ERROR, 0, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1612 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1613 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1614 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1619 * Successfully restored xattr.
1624 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1625 (used_bytes = (bp - jcr->xattr_data)) >= total_bytes) {
1629 if (used_bytes < (total_bytes - 1))
1633 * Restore the actual xattr.
1635 if (!is_extensible) {
1636 unlinkat(attrdirfd, target_attrname, 0);
1639 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1641 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1642 target_attrname, jcr->last_fname, be.bstrerror());
1643 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1644 target_attrname, jcr->last_fname, be.bstrerror());
1650 * Restore the actual data.
1652 if (st.st_size > 0) {
1653 used_bytes = (data - jcr->xattr_data);
1654 cnt = total_bytes - used_bytes;
1657 * Do a sanity check, the st.st_size should be the same as the number of bytes
1658 * we have available as data of the stream.
1660 if (cnt != st.st_size) {
1661 Jmsg2(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
1662 target_attrname, jcr->last_fname);
1663 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1664 target_attrname, jcr->last_fname);
1669 cnt = write(attrfd, data, cnt);
1672 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
1673 target_attrname, jcr->last_fname, be.bstrerror());
1674 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
1675 target_attrname, jcr->last_fname, be.bstrerror());
1681 cnt = total_bytes - used_bytes;
1687 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1691 if (symlink(linked_target, target_attrname) < 0) {
1693 Jmsg4(jcr, M_ERROR, 0, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
1694 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1695 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
1696 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1701 * Successfully restored xattr.
1710 * Restore owner and acl for non extensible attributes.
1712 if (!is_extensible) {
1713 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
1717 * Gentile way of the system saying this type of xattr layering is not supported.
1718 * But as this is not an error we return a positive return value.
1724 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1725 target_attrname, jcr->last_fname, be.bstrerror());
1726 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1727 target_attrname, jcr->last_fname, be.bstrerror());
1734 if (acl_text && *acl_text)
1735 if (!solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text))
1737 #endif /* HAVE_ACL */
1740 * For a non extensible attribute restore access and modification time on the xattr.
1742 if (!is_extensible) {
1743 times[0].tv_sec = st.st_atime;
1744 times[0].tv_usec = 0;
1745 times[1].tv_sec = st.st_mtime;
1746 times[1].tv_usec = 0;
1748 if (futimesat(attrdirfd, target_attrname, times) < 0) {
1750 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
1751 target_attrname, jcr->last_fname, be.bstrerror());
1752 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
1753 target_attrname, jcr->last_fname, be.bstrerror());
1759 * Successfully restored xattr.
1765 Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
1767 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
1774 if (attrdirfd != -1) {
1783 static bool solaris_extract_xattr(JCR *jcr, int stream)
1786 bool is_extensible = false;
1790 * First make sure we can restore xattr on the filesystem.
1793 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1794 case STREAM_XATTR_SOLARIS_SYS:
1795 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1796 Qmsg1(jcr, M_WARNING, 0,
1797 _("Failed to restore extensible attributes on file \"%s\"\n"),
1799 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1804 is_extensible = true;
1807 case STREAM_XATTR_SOLARIS:
1808 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1809 Qmsg1(jcr, M_WARNING, 0,
1810 _("Failed to restore extended attributes on file \"%s\"\n"),
1812 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1822 * As we change the cwd in the restore function save the current cwd
1823 * for restore after return from the solaris_restore_xattrs function.
1825 getcwd(cwd, sizeof(cwd));
1826 retval = solaris_restore_xattrs(jcr, is_extensible);
1831 static int solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1837 * First see if extended attributes or extensible attributes are present.
1838 * If not just pretend things went ok.
1840 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1844 * As we change the cwd in the save function save the current cwd
1845 * for restore after return from the solaris_save_xattrs function.
1847 getcwd(cwd, sizeof(cwd));
1848 retval = solaris_save_xattrs(jcr, NULL, NULL);
1850 drop_xattr_link_cache();
1856 static bool solaris_parse_xattr_stream(JCR *jcr, int stream)
1859 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1860 case STREAM_XATTR_SOLARIS_SYS:
1862 case STREAM_XATTR_SOLARIS:
1863 return solaris_extract_xattr(jcr, stream);
1865 Jmsg2(jcr, M_WARNING, 0,
1866 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1867 jcr->last_fname, stream);
1868 return true; /* non-fatal error */
1873 bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1875 #if defined(HAVE_SUN_OS)
1876 return solaris_build_xattr_streams(jcr, ff_pkt);
1877 #elif defined(HAVE_DARWIN_OS)
1878 return darwin_build_xattr_streams(jcr, ff_pkt);
1879 #elif defined(HAVE_FREEBSD_OS)
1880 return freebsd_build_xattr_streams(jcr, ff_pkt);
1881 #elif defined(HAVE_LINUX_OS)
1882 return linux_build_xattr_streams(jcr, ff_pkt);
1883 #elif defined(HAVE_NETBSD_OS)
1884 return netbsd_build_xattr_streams(jcr, ff_pkt);
1888 bool parse_xattr_stream(JCR *jcr, int stream)
1891 * Based on the stream being passed in dispatch to the right function
1892 * for parsing and restoring a specific xattr. The platform determines
1893 * which streams are recognized and parsed and which are handled by
1894 * the default case and ignored. As only one of the platform defines
1895 * is true per compile we never end up with duplicate switch values.
1898 #if defined(HAVE_SUN_OS)
1899 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1900 case STREAM_XATTR_SOLARIS_SYS:
1902 case STREAM_XATTR_SOLARIS:
1903 return solaris_parse_xattr_stream(jcr, stream);
1904 #elif defined(HAVE_DARWIN_OS)
1905 case STREAM_XATTR_DARWIN:
1906 return darwin_parse_xattr_stream(jcr, stream);
1907 #elif defined(HAVE_FREEBSD_OS)
1908 case STREAM_XATTR_FREEBSD:
1909 return freebsd_parse_xattr_stream(jcr, stream);
1910 #elif defined(HAVE_LINUX_OS)
1911 case STREAM_XATTR_LINUX:
1912 return linux_parse_xattr_stream(jcr, stream);
1913 #elif defined(HAVE_NETBSD_OS)
1914 case STREAM_XATTR_NETBSD:
1915 return netbsd_parse_xattr_stream(jcr, stream);
1919 * Issue a warning and discard the message. But pretend the restore was ok.
1921 Qmsg2(jcr, M_WARNING, 0,
1922 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1923 jcr->last_fname, stream);
1925 } /* end switch (stream) */