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
51 * List of supported OSes. Everything outside that gets stub functions.
52 * Also when XATTR support is explicitly disabled.
54 #if !defined(HAVE_XATTR) /* Extended Attributes support is required, of course */ \
55 || !( defined(HAVE_DARWIN_OS) /* OSX has XATTR support using getxattr etc. */ \
56 || defined(HAVE_FREEBSD_OS) /* FreeBSD has XATTR support using lgetxattr etc. */ \
57 || defined(HAVE_LINUX_OS) /* Linux has XATTR support using the lgetxattr etc. */ \
58 || defined(HAVE_NETBSD_OS) /* NetBSD has XATTR support using the lgetxattr etc. */ \
59 || defined(HAVE_SUN_OS) /* Solaris has XATTR support using attropen etc. */ \
62 bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
64 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
68 bool parse_xattr_stream(JCR *jcr, int stream)
70 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
77 * Send a XATTR stream to the SD.
79 static bool send_xattr_stream(JCR *jcr, int stream)
81 BSOCK *sd = jcr->store_bsock;
83 #ifdef FD_NO_SEND_TEST
90 if (jcr->xattr_data_len <= 0)
96 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
97 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
103 * Send the buffer to the storage deamon
105 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data);
107 sd->msg = jcr->xattr_data;
108 sd->msglen = jcr->xattr_data_len;
112 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
117 jcr->JobBytes += sd->msglen;
119 if (!sd->signal(BNET_EOD)) {
120 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
124 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
130 * This is a supported OS, See what kind of interface we should use.
131 * Start with the generic interface used by most OS-es.
133 #if defined(HAVE_DARWIN_OS) \
134 || defined(HAVE_FREEBSD_OS) \
135 || defined(HAVE_LINUX_OS) \
136 || defined(HAVE_NETBSD_OS)
138 #ifdef HAVE_SYS_XATTR_H
139 #include <sys/xattr.h>
143 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
144 * listxattr, getxattr and setxattr with an extra options argument
145 * which mimics the l variants of the functions when we specify
146 * XATTR_NOFOLLOW as the options value.
148 #if defined(HAVE_DARWIN_OS)
149 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
150 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
151 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
154 * Fallback to the non l-functions when those are not available.
156 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
157 #define lgetxattr getxattr
159 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
160 #define lsetxattr setxattr
162 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
163 #define llistxattr listxattr
167 static void xattr_drop_internal_table(xattr_t *xattr_value_list)
169 xattr_t *current_xattr;
172 * Walk the list of xattrs and free allocated memory on traversing.
174 for (current_xattr = xattr_value_list;
175 current_xattr != (xattr_t *)NULL;
178 * See if we can shortcut.
180 if (current_xattr->magic != XATTR_MAGIC)
183 free(current_xattr->name);
185 if (current_xattr->value_length > 0)
186 free(current_xattr->value);
190 * Free the array of control structs.
192 free(xattr_value_list);
196 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
197 * which encodes one or more xattr_t structures.
199 * The Serialized stream consists of the following elements:
200 * magic - A magic string which makes it easy to detect any binary incompatabilites
201 * name_length - The length of the following xattr name
202 * name - The name of the extended attribute
203 * value_length - The length of the following xattr data
204 * value - The actual content of the extended attribute
206 * This is repeated 1 or more times.
209 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list)
211 xattr_t *current_xattr;
215 * Make sure the serialized stream fits in the poolmem buffer.
216 * We allocate some more to be sure the stream is gonna fit.
218 jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, expected_serialize_len + 10);
219 ser_begin(jcr->xattr_data, expected_serialize_len + 10);
222 * Walk the list of xattrs and serialize the data.
224 for (current_xattr = xattr_value_list; current_xattr != (xattr_t *)NULL; current_xattr++) {
226 * See if we can shortcut.
228 if (current_xattr->magic != XATTR_MAGIC)
231 ser_uint32(current_xattr->magic);
232 ser_uint32(current_xattr->name_length);
233 ser_bytes(current_xattr->name, current_xattr->name_length);
235 ser_uint32(current_xattr->value_length);
236 ser_bytes(current_xattr->value, current_xattr->value_length);
239 ser_end(jcr->xattr_data, expected_serialize_len + 10);
240 jcr->xattr_data_len = ser_length(jcr->xattr_data);
242 return jcr->xattr_data_len;
245 static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
248 int32_t xattr_list_len,
250 uint32_t expected_serialize_len = 0;
251 char *xattr_list, *bp;
252 xattr_t *xattr_value_list, *current_xattr;
255 * First get the length of the available list with extended attributes.
257 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
258 if (xattr_list_len < 0) {
260 Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
261 jcr->last_fname, be.bstrerror());
262 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
263 jcr->last_fname, be.bstrerror());
264 return true; /* non-fatal return */
265 } else if (xattr_list_len == 0) {
270 * Allocate room for the extented attribute list.
272 xattr_list = (char *)malloc(xattr_list_len + 1);
273 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
276 * Get the actual list of extended attributes names for a file.
278 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
279 if (xattr_list_len < 0) {
281 Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
282 jcr->last_fname, be.bstrerror());
283 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
284 jcr->last_fname, be.bstrerror());
286 return true; /* non-fatal return */
288 xattr_list[xattr_list_len] = '\0';
291 * Count the number of extended attributes on a file.
294 while ((bp - xattr_list) + 1 < xattr_list_len) {
295 #if defined(HAVE_LINUX_OS)
297 * On Linux you also get the acls in the extented attribute list.
298 * So we check if we are already backing up acls and if we do we
299 * don't store the extended attribute with the same info.
301 if ((ff_pkt->flags & FO_ACL) == 0 || strcmp(bp, "system.posix_acl_access"))
307 bp = strchr(bp, '\0') + 1;
317 * Allocate enough room to hold all extended attributes.
318 * After allocating the storage make sure its empty by zeroing it.
320 xattr_value_list = (xattr_t *)malloc(count * sizeof(xattr_t));
321 memset((caddr_t)xattr_value_list, 0, count * sizeof(xattr_t));
324 * Walk the list of extended attributes names and retrieve the data.
325 * We already count the bytes needed for serializing the stream later on.
327 current_xattr = xattr_value_list;
329 while ((bp - xattr_list) + 1 < xattr_list_len) {
330 #if defined(HAVE_LINUX_OS)
331 if (ff_pkt->flags & FO_ACL && !strcmp(bp, "system.posix_acl_access")) {
332 bp = strchr(bp, '\0') + 1;
338 * Each xattr valuepair starts with a magic so we can parse it easier.
340 current_xattr->magic = XATTR_MAGIC;
341 expected_serialize_len += sizeof(current_xattr->magic);
344 * Allocate space for storing the name.
346 current_xattr->name_length = strlen(bp);
347 current_xattr->name = (char *)malloc(current_xattr->name_length);
348 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
350 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
353 * First see how long the value is for the extended attribute.
355 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
356 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());
366 * Allocate space for storing the value.
368 current_xattr->value = (char *)malloc(xattr_value_len);
369 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
371 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
372 if (xattr_value_len < 0) {
374 Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
375 jcr->last_fname, be.bstrerror());
376 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
377 jcr->last_fname, be.bstrerror());
382 * Store the actual length of the value.
384 current_xattr->value_length = xattr_value_len;
385 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
388 * Protect ourself against things getting out of hand.
390 if (expected_serialize_len >= MAX_XATTR_STREAM) {
391 Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
392 jcr->last_fname, MAX_XATTR_STREAM);
400 bp = strchr(bp, '\0') + 1;
404 * Serialize the datastream.
406 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
407 Jmsg1(jcr, M_ERROR, 0, _("Failed to serialize extended attributes on file \"%s\"\n"),
409 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
414 xattr_drop_internal_table(xattr_value_list);
418 * Send the datastream to the SD.
420 return send_xattr_stream(jcr, stream);
423 xattr_drop_internal_table(xattr_value_list);
425 return true; /* non-fatal return */
428 static bool generic_xattr_parse_streams(JCR *jcr)
431 xattr_t current_xattr;
432 bool retval = true; /* default non-fatal */
435 * Parse the stream and perform the setxattr calls on the file.
437 * Start unserializing the data. We keep on looping while we have not
438 * unserialized all bytes in the stream.
440 unser_begin(jcr->xattr_data, jcr->xattr_data_len);
441 while (unser_length(jcr->xattr_data) < jcr->xattr_data_len) {
443 * First make sure the magic is present. This way we can easily catch corruption.
444 * Any missing MAGIC is fatal we do NOT try to continue.
446 unser_uint32(current_xattr.magic);
447 if (current_xattr.magic != XATTR_MAGIC) {
448 Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
450 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
452 return true; /* non-fatal return */
456 * Decode the valuepair. First decode the length of the name.
458 unser_uint32(current_xattr.name_length);
461 * Allocate room for the name and decode its content.
463 current_xattr.name = (char *)malloc(current_xattr.name_length + 1);
464 unser_bytes(current_xattr.name, current_xattr.name_length);
467 * The xattr_name needs to be null terminated for lsetxattr.
469 current_xattr.name[current_xattr.name_length] = '\0';
472 * Decode the value length.
474 unser_uint32(current_xattr.value_length);
477 * Allocate room for the value and decode its content.
479 current_xattr.value = (char *)malloc(current_xattr.value_length);
480 unser_bytes(current_xattr.value, current_xattr.value_length);
483 * Try to set the extended attribute on the file.
484 * If we fail to set this attribute we flag the error but its not fatal,
485 * we try to restore the other extended attributes too.
487 if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
488 current_xattr.value_length, 0) != 0) {
490 Jmsg2(jcr, M_ERROR, 0, _("lsetxattr error on file \"%s\": ERR=%s\n"),
491 jcr->last_fname, be.bstrerror());
492 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
493 jcr->last_fname, be.bstrerror());
497 * Free the temporary buffers.
499 free(current_xattr.name);
500 free(current_xattr.value);
503 unser_end(jcr->xattr_data, jcr->xattr_data_len);
507 #if defined(HAVE_DARWIN_OS)
508 static bool darwin_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
510 return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_DARWIN);
513 static bool darwin_parse_xattr_stream(JCR *jcr, int stream)
516 case STREAM_XATTR_DARWIN:
517 return generic_xattr_parse_streams(jcr);
519 Jmsg2(jcr, M_WARNING, 0,
520 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
521 jcr->last_fname, stream);
522 return true; /* non-fatal error */
525 #elif defined(HAVE_FREEBSD_OS)
526 static bool freebsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
528 return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_FREEBSD);
531 static bool freebsd_parse_xattr_stream(JCR *jcr, int stream)
534 case STREAM_XATTR_FREEBSD:
535 return generic_xattr_parse_streams(jcr);
537 Jmsg2(jcr, M_WARNING, 0,
538 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
539 jcr->last_fname, stream);
540 return true; /* non-fatal error */
543 #elif defined(HAVE_LINUX_OS)
544 static bool linux_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
546 return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_LINUX);
549 static bool linux_parse_xattr_stream(JCR *jcr, int stream)
552 case STREAM_XATTR_LINUX:
553 return generic_xattr_parse_streams(jcr);
555 Jmsg2(jcr, M_WARNING, 0,
556 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
557 jcr->last_fname, stream);
558 return true; /* non-fatal error */
561 #elif defined(HAVE_NETBSD_OS)
562 static bool netbsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
564 return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_NETBSD);
567 static bool netbsd_parse_xattr_stream(JCR *jcr, int stream)
570 case STREAM_XATTR_NETBSD:
571 return generic_xattr_parse_streams(jcr);
573 Jmsg2(jcr, M_WARNING, 0,
574 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
575 jcr->last_fname, stream);
576 return true; /* non-fatal error */
580 #elif defined(HAVE_SUN_OS)
582 * Solaris extended attributes were introduced in Solaris 9
585 * Solaris extensible attributes were introduced in OpenSolaris
586 * by PSARC 2007/315 Solaris extensible attributes are also
587 * sometimes called extended system attributes.
589 * man fsattr(5) on Solaris gives a wealth of info. The most
590 * important bits are:
592 * Attributes are logically supported as files within the file
593 * system. The file system is therefore augmented with an
594 * orthogonal name space of file attributes. Any file (includ-
595 * ing attribute files) can have an arbitrarily deep attribute
596 * tree associated with it. Attribute values are accessed by
597 * file descriptors obtained through a special attribute inter-
598 * face. This logical view of "attributes as files" allows the
599 * leveraging of existing file system interface functionality
600 * to support the construction, deletion, and manipulation of
603 * The special files "." and ".." retain their accustomed
604 * semantics within the attribute hierarchy. The "." attribute
605 * file refers to the current directory and the ".." attribute
606 * file refers to the parent directory. The unnamed directory
607 * at the head of each attribute tree is considered the "child"
608 * of the file it is associated with and the ".." file refers
609 * to the associated file. For any non-directory file with
610 * attributes, the ".." entry in the unnamed directory refers
611 * to a file that is not a directory.
613 * Conceptually, the attribute model is fully general. Extended
614 * attributes can be any type of file (doors, links, direc-
615 * tories, and so forth) and can even have their own attributes
616 * (fully recursive). As a result, the attributes associated
617 * with a file could be an arbitrarily deep directory hierarchy
618 * where each attribute could have an equally complex attribute
619 * tree associated with it. Not all implementations are able
620 * to, or want to, support the full model. Implementation are
621 * therefore permitted to reject operations that are not sup-
622 * ported. For example, the implementation for the UFS file
623 * system allows only regular files as attributes (for example,
624 * no sub-directories) and rejects attempts to place attributes
627 * The following list details the operations that are rejected
628 * in the current implementation:
630 * link Any attempt to create links between
631 * attribute and non-attribute space
632 * is rejected to prevent security-
633 * related or otherwise sensitive
634 * attributes from being exposed, and
635 * therefore manipulable, as regular
638 * rename Any attempt to rename between
639 * attribute and non-attribute space
640 * is rejected to prevent an already
641 * linked file from being renamed and
642 * thereby circumventing the link res-
645 * mkdir, symlink, mknod Any attempt to create a "non-
646 * regular" file in attribute space is
647 * rejected to reduce the functional-
648 * ity, and therefore exposure and
649 * risk, of the initial implementa-
652 * The entire available name space has been allocated to "gen-
653 * eral use" to bring the implementation in line with the NFSv4
654 * draft standard [NFSv4]. That standard defines "named attri-
655 * butes" (equivalent to Solaris Extended Attributes) with no
656 * naming restrictions. All Sun applications making use of
657 * opaque extended attributes will use the prefix "SUNW".
660 #ifdef HAVE_SYS_ATTR_H
661 #include <sys/attr.h>
668 #ifdef HAVE_SYS_NVPAIR_H
669 #include <sys/nvpair.h>
672 #ifdef HAVE_SYS_ACL_H
677 * This is the count of xattrs saved on a certain file, it gets reset
678 * on each new file processed and is used to see if we need to send
679 * the hidden xattr dir data. We only send that data when we encounter
680 * an other xattr on the file.
682 static int nr_xattr_saved = 0;
683 static char toplevel_hidden_dir_xattr_data[MAXSTRING];
684 static int toplevel_hidden_dir_xattr_data_len;
687 * This code creates a temporary cache with entries for each xattr which has
688 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
690 static xattr_link_cache_entry_t *xattr_link_cache_head = NULL,
691 *xattr_link_cache_tail = NULL;
693 static struct xattr_link_cache_entry *find_xattr_link_cache_entry(ino_t inum)
695 xattr_link_cache_entry_t *ptr;
697 for (ptr = xattr_link_cache_head; ptr != NULL; ptr = ptr->next) {
698 if (ptr->inum == inum) {
705 static void add_xattr_link_cache_entry(ino_t inum, char *target)
707 xattr_link_cache_entry_t *ptr;
709 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(struct xattr_link_cache_entry));
710 memset((caddr_t)ptr, 0, sizeof(struct xattr_link_cache_entry));
712 strncpy(ptr->target, target, sizeof(ptr->target));
713 if (xattr_link_cache_head == NULL) {
714 xattr_link_cache_head = ptr;
716 if (xattr_link_cache_tail != NULL)
717 xattr_link_cache_tail->next = ptr;
721 static void drop_xattr_link_cache(void)
723 xattr_link_cache_entry_t *ptr, *next;
725 for (ptr = xattr_link_cache_tail; ptr != NULL; ptr = next) {
729 xattr_link_cache_head = NULL;
730 xattr_link_cache_tail = NULL;
733 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
735 * This function returns true if a non default extended system attribute
736 * list is associated with fd and returns false when an error has occured
737 * or when only extended system attributes other than archive,
738 * av_modified or crtime are set.
740 * The function returns true for the following cases:
742 * - any extended system attribute other than the default attributes
743 * ('archive', 'av_modified' and 'crtime') is set
744 * - nvlist has NULL name string
745 * - nvpair has data type of 'nvlist'
746 * - default data type.
748 static bool solaris_has_non_transient_extensible_attributes(int fd)
758 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
763 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
764 name = nvpair_name(pair);
767 fattr = name_to_attr(name);
773 type = nvpair_type(pair);
775 case DATA_TYPE_BOOLEAN_VALUE:
776 if (nvpair_value_boolean_value(pair, &value) != 0) {
779 if (value && fattr != F_ARCHIVE &&
780 fattr != F_AV_MODIFIED) {
785 case DATA_TYPE_UINT64_ARRAY:
786 if (fattr != F_CRTIME) {
791 case DATA_TYPE_NVLIST:
799 if (response != NULL) {
800 nvlist_free(response);
804 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
806 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
808 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
809 * There is no need to store those acls as we already store the stat bits too.
811 static bool acl_is_trivial(int count, aclent_t *entries)
816 for (n = 0; n < count; n++) {
818 if (!(ace->a_type == USER_OBJ ||
819 ace->a_type == GROUP_OBJ ||
820 ace->a_type == OTHER_OBJ ||
821 ace->a_type == CLASS_OBJ))
826 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
828 static bool solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
831 #ifdef HAVE_EXTENDED_ACL
836 * See if this attribute has an ACL
838 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
839 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
841 * See if there is a non trivial acl on the file.
843 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
844 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
846 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
847 attrname, jcr->last_fname, be.bstrerror());
848 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
849 attrname, jcr->last_fname, be.bstrerror());
850 return true; /* non-fatal */
854 #if defined(ACL_SID_FMT)
856 * New format flag added in newer Solaris versions.
858 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
860 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
861 #endif /* ACL_SID_FMT */
863 *acl_text = acl_totext(aclp, flags);
873 #else /* HAVE_EXTENDED_ACL */
875 aclent_t *acls = NULL;
878 * See if this attribute has an ACL
881 n = facl(fd, GETACLCNT, 0, NULL);
883 n = acl(attrname, GETACLCNT, 0, NULL);
886 if (n >= MIN_ACL_ENTRIES) {
887 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
888 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
889 acl(attrname, GETACL, n, acls) != n) {
891 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
892 attrname, jcr->last_fname, be.bstrerror());
893 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
894 attrname, jcr->last_fname, be.bstrerror());
896 return true; /* non-fatal */
900 * See if there is a non trivial acl on the file.
902 if (!acl_is_trivial(n, acls)) {
903 if ((*acl_text = acltotext(acls, n)) == NULL) {
905 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
906 attrname, jcr->last_fname, be.bstrerror());
907 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
908 attrname, jcr->last_fname, be.bstrerror());
910 return true; /* non-fatal */
922 #endif /* HAVE_EXTENDED_ACL */
925 return false; /* fatal return */
926 #endif /* HAVE_ACL */
930 * Forward declaration for recursive function call.
932 static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
935 * Save an extended or extensible attribute.
936 * This is stored as an opaque stream of bytes with the following encoding:
938 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
940 * or for a hardlinked or symlinked attribute
942 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
944 * xattr_name can be a subpath relative to the file the xattr is on.
945 * stat_buffer is the string representation of the stat struct.
946 * acl_string is an acl text when a non trivial acl is set on the xattr.
947 * actual_xattr_data is the content of the xattr file.
949 static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
950 const char *attrname, bool toplevel_hidden_dir, int stream)
955 struct xattr_link_cache_entry *xlce;
956 char target_attrname[PATH_MAX];
957 char link_source[PATH_MAX];
958 char *acl_text = NULL;
959 char attribs[MAXSTRING];
961 bool retval = true; /* default is non-fatal */
963 snprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
966 * Get the stats of the extended or extensible attribute.
968 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
970 Jmsg3(jcr, M_ERROR, 0, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
971 target_attrname, jcr->last_fname, be.bstrerror());
972 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
973 target_attrname, jcr->last_fname, be.bstrerror());
978 * Based on the filetype perform the correct action. We support most filetypes here, more
979 * then the actual implementation on Solaris supports so some code may never get executed
980 * due to limitations in the implementation.
982 switch (st.st_mode & S_IFMT) {
987 * Get any acl on the xattr.
989 if (!solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text))
993 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
994 * Encode the stat struct into an ASCII representation.
996 encode_stat(attribs, &st, 0, stream);
997 cnt = snprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
998 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1003 * Get any acl on the xattr.
1005 if (!solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text))
1009 * See if this is the toplevel_hidden_dir being saved.
1011 if (toplevel_hidden_dir) {
1013 * Save the data for later storage when we encounter a real xattr.
1014 * Encode the stat struct into an ASCII representation and jump out of the function.
1016 encode_stat(attribs, &st, 0, stream);
1017 toplevel_hidden_dir_xattr_data_len = snprintf(toplevel_hidden_dir_xattr_data,
1018 sizeof(toplevel_hidden_dir_xattr_data),
1020 target_attrname, 0, attribs, 0,
1021 (acl_text) ? acl_text : "", 0);
1025 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1026 * Encode the stat struct into an ASCII representation.
1028 encode_stat(attribs, &st, 0, stream);
1029 cnt = snprintf(buffer, sizeof(buffer),
1031 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1036 * If this is a hardlinked file check the inode cache for a hit.
1038 if (st.st_nlink > 1) {
1040 * See if the cache already knows this inode number.
1042 if ((xlce = find_xattr_link_cache_entry(st.st_ino)) != NULL) {
1044 * Generate a xattr encoding with the reference to the target in there.
1046 encode_stat(attribs, &st, st.st_ino, stream);
1047 cnt = snprintf(buffer, sizeof(buffer),
1049 target_attrname, 0, attribs, 0, xlce->target, 0);
1050 pm_memcpy(jcr->xattr_data, buffer, cnt);
1051 jcr->xattr_data_len = cnt;
1052 retval = send_xattr_stream(jcr, stream);
1055 * For a hard linked file we are ready now, no need to recursively save the attributes.
1061 * Store this hard linked file in the cache.
1062 * Store the name relative to the top level xattr space.
1064 add_xattr_link_cache_entry(st.st_ino, target_attrname + 1);
1068 * Get any acl on the xattr.
1070 if (!solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text)) {
1075 * Encode the stat struct into an ASCII representation.
1077 encode_stat(attribs, &st, 0, stream);
1078 cnt = snprintf(buffer, sizeof(buffer),
1080 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1083 * Open the extended or extensible attribute file.
1085 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1087 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1088 target_attrname, jcr->last_fname, be.bstrerror());
1089 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1090 target_attrname, jcr->last_fname, be.bstrerror());
1097 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1098 * Encode the stat struct into an ASCII representation.
1100 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1102 Jmsg3(jcr, M_ERROR, 0, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1103 target_attrname, jcr->last_fname, be.bstrerror());
1104 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1105 target_attrname, jcr->last_fname, be.bstrerror());
1110 * Generate a xattr encoding with the reference to the target in there.
1112 encode_stat(attribs, &st, st.st_ino, stream);
1113 cnt = snprintf(buffer, sizeof(buffer),
1115 target_attrname, 0, attribs, 0, link_source, 0);
1116 pm_memcpy(jcr->xattr_data, buffer, cnt);
1117 jcr->xattr_data_len = cnt;
1118 retval = send_xattr_stream(jcr, stream);
1121 * For a soft linked file we are ready now, no need to recursively save the attributes.
1130 * See if this is the first real xattr being saved. If it is save the toplevel_hidden_dir attributes first.
1132 if (nr_xattr_saved == 0) {
1133 pm_memcpy(jcr->xattr_data, toplevel_hidden_dir_xattr_data, toplevel_hidden_dir_xattr_data_len);
1134 jcr->xattr_data_len = toplevel_hidden_dir_xattr_data_len;
1135 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1138 pm_memcpy(jcr->xattr_data, buffer, cnt);
1139 jcr->xattr_data_len = cnt;
1142 * Only dump the content of regular files.
1144 switch (st.st_mode & S_IFMT) {
1146 if (st.st_size > 0) {
1148 * Protect ourself against things getting out of hand.
1150 if (st.st_size >= MAX_XATTR_STREAM) {
1151 Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1152 jcr->last_fname, MAX_XATTR_STREAM);
1156 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1157 jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, jcr->xattr_data_len + cnt);
1158 memcpy(jcr->xattr_data + jcr->xattr_data_len, buffer, cnt);
1159 jcr->xattr_data_len += cnt;
1163 Jmsg2(jcr, M_ERROR, 0, _("Unable to read content of xattr %s on file \"%s\"\n"),
1164 target_attrname, jcr->last_fname);
1165 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1166 target_attrname, jcr->last_fname);
1177 retval = send_xattr_stream(jcr, stream);
1182 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1183 * available on this extended attribute.
1186 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1189 * The recursive call could change our working dir so change back to the wanted workdir.
1191 if (fchdir(fd) < 0) {
1193 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1194 jcr->last_fname, be.bstrerror());
1195 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1196 jcr->last_fname, fd, be.bstrerror());
1211 static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1214 int fd, filefd = -1, attrdirfd = -1;
1217 char current_xattr_namespace[PATH_MAX];
1218 bool retval = true; /* default non-fatal error */
1221 * Determine what argument to use. Use attr_parent when set
1222 * (recursive call) or jcr->last_fname for first call. Also save
1223 * the current depth of the xattr_space we are in.
1227 if (xattr_namespace) {
1228 snprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1229 xattr_namespace, attr_parent);
1231 strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1234 name = jcr->last_fname;
1235 strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1239 * Open the file on which to save the xattrs read-only.
1241 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1243 Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1244 jcr->last_fname, be.bstrerror());
1245 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1246 jcr->last_fname, be.bstrerror());
1251 * Open the xattr naming space.
1253 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1257 * Gentile way of the system saying this type of xattr layering is not supported.
1258 * Which is not problem we just forget about this this xattr.
1259 * But as this is not an error we return a positive return value.
1265 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1266 name, jcr->last_fname, be.bstrerror());
1267 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1268 name, jcr->last_fname, be.bstrerror());
1274 * We need to change into the attribute directory to determine if each of the
1275 * attributes should be saved.
1277 if (fchdir(attrdirfd) < 0) {
1279 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1280 jcr->last_fname, be.bstrerror());
1281 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1282 jcr->last_fname, attrdirfd, be.bstrerror());
1287 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1288 * else because the readdir returns "." entry after the extensible attr entry.
1289 * And as we want this entry before anything else we better just save its data.
1292 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1293 true, STREAM_XATTR_SOLARIS);
1295 if ((fd = dup(attrdirfd)) == -1 ||
1296 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1298 Jmsg2(jcr, M_ERROR, 0, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1299 jcr->last_fname, be.bstrerror());
1300 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1301 jcr->last_fname, fd, be.bstrerror());
1307 * Walk the namespace.
1309 while (dp = readdir(dirp)) {
1311 * Skip only the toplevel . dir.
1313 if (!attr_parent && !strcmp(dp->d_name, "."))
1317 * Skip all .. directories
1319 if (!strcmp(dp->d_name, ".."))
1322 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1323 current_xattr_namespace, dp->d_name, jcr->last_fname);
1325 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1327 * We are not interested in read-only extensible attributes.
1329 if (!strcmp(dp->d_name, VIEW_READONLY)) {
1330 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1331 current_xattr_namespace, dp->d_name, jcr->last_fname);
1337 * We are only interested in read-write extensible attributes
1338 * when they contain non-transient values.
1340 if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1342 * Determine if there are non-transient system attributes at the toplevel.
1343 * We need to provide a fd to the open file.
1345 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1346 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1347 current_xattr_namespace, dp->d_name, jcr->last_fname);
1354 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1355 false, STREAM_XATTR_SOLARIS_SYS);
1358 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1363 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1364 false, STREAM_XATTR_SOLARIS);
1371 if (attrdirfd != -1)
1379 static bool solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1381 #ifdef HAVE_EXTENDED_ACL
1385 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1386 Jmsg1(jcr, M_ERROR, 0, _("Unable to convert acl from text on file \"%s\"\n"
1388 return true; /* non-fatal */
1391 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1392 acl_set(attrname, aclp) != 0) {
1394 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1395 attrname, jcr->last_fname, be.bstrerror());
1396 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1397 attrname, jcr->last_fname, be.bstrerror());
1398 return true; /* non-fatal */
1406 #else /* HAVE_EXTENDED_ACL */
1408 aclent_t *acls = NULL;
1410 acls = aclfromtext(acl_text, &n);
1412 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1413 acl(attrname, SETACL, n, acls) != 0) {
1415 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1416 attrname, jcr->last_fname, be.bstrerror());
1417 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1418 attrname, jcr->last_fname, be.bstrerror());
1419 return true; /* non-fatal */
1428 #endif /* HAVE_EXTENDED_ACL */
1431 #endif /* HAVE_ACL */
1433 static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1435 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1436 int used_bytes, total_bytes, cnt;
1437 char *bp, *target_attrname, *attribs;
1438 char *linked_target = NULL;
1439 char *acl_text = NULL;
1443 struct timeval times[2];
1444 bool retval = true; /* default non-fatal */
1447 * Parse the xattr stream. First the part that is the same for all xattrs.
1450 total_bytes = jcr->xattr_data_len;
1453 * The name of the target xattr has a leading / we are not interested
1454 * in that so skip it when decoding the string. We always start a the /
1455 * of the xattr space anyway.
1457 target_attrname = jcr->xattr_data + 1;
1458 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1459 (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1465 * Open the file on which to restore the xattrs read-only.
1467 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1469 Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1470 jcr->last_fname, be.bstrerror());
1471 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1472 jcr->last_fname, be.bstrerror());
1477 * Open the xattr naming space and make it the current working dir.
1479 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1481 Jmsg2(jcr, M_ERROR, 0, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1482 jcr->last_fname, be.bstrerror());
1483 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1484 jcr->last_fname, be.bstrerror());
1488 if (fchdir(attrdirfd) < 0) {
1490 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1491 jcr->last_fname, be.bstrerror());
1492 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1493 jcr->last_fname, attrdirfd, be.bstrerror());
1498 * Try to open the correct xattr subdir based on the target_attrname given.
1499 * e.g. check if its a subdir attrname. Each / in the string makes us go
1502 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1505 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1507 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1508 target_attrname, jcr->last_fname, be.bstrerror());
1509 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1510 target_attrname, jcr->last_fname, be.bstrerror());
1518 * Open the xattr naming space.
1520 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1522 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1523 target_attrname, jcr->last_fname, be.bstrerror());
1524 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1525 target_attrname, jcr->last_fname, be.bstrerror());
1533 * Make the xattr space our current workingdir.
1535 if (fchdir(attrdirfd) < 0) {
1537 Jmsg3(jcr, M_ERROR, 0, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1538 target_attrname, jcr->last_fname, be.bstrerror());
1539 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1540 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1544 target_attrname = ++bp;
1548 * Decode the attributes from the stream.
1550 decode_stat(attribs, &st, &inum);
1553 * Decode the next field (acl_text).
1555 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1556 (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1562 * Based on the filetype perform the correct action. We support most filetypes here, more
1563 * then the actual implementation on Solaris supports so some code may never get executed
1564 * due to limitations in the implementation.
1566 switch (st.st_mode & S_IFMT) {
1569 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1571 unlinkat(attrdirfd, target_attrname, 0);
1572 if (mkfifo(target_attrname, st.st_mode) < 0) {
1574 Jmsg3(jcr, M_ERROR, 0, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1575 target_attrname, jcr->last_fname, be.bstrerror());
1576 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1577 target_attrname, jcr->last_fname, be.bstrerror());
1584 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1586 unlinkat(attrdirfd, target_attrname, 0);
1587 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1589 Jmsg3(jcr, M_ERROR, 0, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1590 target_attrname, jcr->last_fname, be.bstrerror());
1591 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1592 target_attrname, jcr->last_fname, be.bstrerror());
1598 * If its not the hidden_dir create the entry.
1599 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1601 if (strcmp(target_attrname, ".")) {
1602 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1603 if (mkdir(target_attrname, st.st_mode) < 0) {
1605 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1606 target_attrname, jcr->last_fname, be.bstrerror());
1607 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1608 target_attrname, jcr->last_fname, be.bstrerror());
1615 * See if this is a hard linked file. e.g. inum != 0
1620 unlinkat(attrdirfd, target_attrname, 0);
1621 if (link(linked_target, target_attrname) < 0) {
1623 Jmsg4(jcr, M_ERROR, 0, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1624 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1625 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1626 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1631 * Successfully restored xattr.
1636 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1637 (used_bytes = (bp - jcr->xattr_data)) >= total_bytes) {
1641 if (used_bytes < (total_bytes - 1))
1645 * Restore the actual xattr.
1647 if (!is_extensible) {
1648 unlinkat(attrdirfd, target_attrname, 0);
1651 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1653 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1654 target_attrname, jcr->last_fname, be.bstrerror());
1655 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1656 target_attrname, jcr->last_fname, be.bstrerror());
1662 * Restore the actual data.
1664 if (st.st_size > 0) {
1665 used_bytes = (data - jcr->xattr_data);
1666 cnt = total_bytes - used_bytes;
1669 * Do a sanity check, the st.st_size should be the same as the number of bytes
1670 * we have available as data of the stream.
1672 if (cnt != st.st_size) {
1673 Jmsg2(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
1674 target_attrname, jcr->last_fname);
1675 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1676 target_attrname, jcr->last_fname);
1681 cnt = write(attrfd, data, cnt);
1684 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
1685 target_attrname, jcr->last_fname, be.bstrerror());
1686 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
1687 target_attrname, jcr->last_fname, be.bstrerror());
1693 cnt = total_bytes - used_bytes;
1699 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1703 if (symlink(linked_target, target_attrname) < 0) {
1705 Jmsg4(jcr, M_ERROR, 0, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
1706 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1707 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
1708 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1713 * Successfully restored xattr.
1722 * Restore owner and acl for non extensible attributes.
1724 if (!is_extensible) {
1725 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
1729 * Gentile way of the system saying this type of xattr layering is not supported.
1730 * But as this is not an error we return a positive return value.
1736 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1737 target_attrname, jcr->last_fname, be.bstrerror());
1738 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1739 target_attrname, jcr->last_fname, be.bstrerror());
1746 if (acl_text && *acl_text)
1747 if (!solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text))
1749 #endif /* HAVE_ACL */
1752 * For a non extensible attribute restore access and modification time on the xattr.
1754 if (!is_extensible) {
1755 times[0].tv_sec = st.st_atime;
1756 times[0].tv_usec = 0;
1757 times[1].tv_sec = st.st_mtime;
1758 times[1].tv_usec = 0;
1760 if (futimesat(attrdirfd, target_attrname, times) < 0) {
1762 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
1763 target_attrname, jcr->last_fname, be.bstrerror());
1764 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
1765 target_attrname, jcr->last_fname, be.bstrerror());
1771 * Successfully restored xattr.
1777 Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
1779 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
1786 if (attrdirfd != -1) {
1795 static bool solaris_extract_xattr(JCR *jcr, int stream)
1798 bool is_extensible = false;
1802 * First make sure we can restore xattr on the filesystem.
1805 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1806 case STREAM_XATTR_SOLARIS_SYS:
1807 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1808 Qmsg1(jcr, M_WARNING, 0,
1809 _("Failed to restore extensible attributes on file \"%s\"\n"),
1811 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1816 is_extensible = true;
1819 case STREAM_XATTR_SOLARIS:
1820 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1821 Qmsg1(jcr, M_WARNING, 0,
1822 _("Failed to restore extended attributes on file \"%s\"\n"),
1824 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1834 * As we change the cwd in the restore function save the current cwd
1835 * for restore after return from the solaris_restore_xattrs function.
1837 getcwd(cwd, sizeof(cwd));
1838 retval = solaris_restore_xattrs(jcr, is_extensible);
1843 static int solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1849 * First see if extended attributes or extensible attributes are present.
1850 * If not just pretend things went ok.
1852 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1856 * As we change the cwd in the save function save the current cwd
1857 * for restore after return from the solaris_save_xattrs function.
1859 getcwd(cwd, sizeof(cwd));
1860 retval = solaris_save_xattrs(jcr, NULL, NULL);
1862 drop_xattr_link_cache();
1868 static bool solaris_parse_xattr_stream(JCR *jcr, int stream)
1871 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1872 case STREAM_XATTR_SOLARIS_SYS:
1874 case STREAM_XATTR_SOLARIS:
1875 return solaris_extract_xattr(jcr, stream);
1877 Jmsg2(jcr, M_WARNING, 0,
1878 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1879 jcr->last_fname, stream);
1880 return true; /* non-fatal error */
1885 bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1887 #if defined(HAVE_SUN_OS)
1888 return solaris_build_xattr_streams(jcr, ff_pkt);
1889 #elif defined(HAVE_DARWIN_OS)
1890 return darwin_build_xattr_streams(jcr, ff_pkt);
1891 #elif defined(HAVE_FREEBSD_OS)
1892 return freebsd_build_xattr_streams(jcr, ff_pkt);
1893 #elif defined(HAVE_LINUX_OS)
1894 return linux_build_xattr_streams(jcr, ff_pkt);
1895 #elif defined(HAVE_NETBSD_OS)
1896 return netbsd_build_xattr_streams(jcr, ff_pkt);
1900 bool parse_xattr_stream(JCR *jcr, int stream)
1903 * Based on the stream being passed in dispatch to the right function
1904 * for parsing and restoring a specific xattr. The platform determines
1905 * which streams are recognized and parsed and which are handled by
1906 * the default case and ignored. As only one of the platform defines
1907 * is true per compile we never end up with duplicate switch values.
1910 #if defined(HAVE_SUN_OS)
1911 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1912 case STREAM_XATTR_SOLARIS_SYS:
1914 case STREAM_XATTR_SOLARIS:
1915 return solaris_parse_xattr_stream(jcr, stream);
1916 #elif defined(HAVE_DARWIN_OS)
1917 case STREAM_XATTR_DARWIN:
1918 return darwin_parse_xattr_stream(jcr, stream);
1919 #elif defined(HAVE_FREEBSD_OS)
1920 case STREAM_XATTR_FREEBSD:
1921 return freebsd_parse_xattr_stream(jcr, stream);
1922 #elif defined(HAVE_LINUX_OS)
1923 case STREAM_XATTR_LINUX:
1924 return linux_parse_xattr_stream(jcr, stream);
1925 #elif defined(HAVE_NETBSD_OS)
1926 case STREAM_XATTR_NETBSD:
1927 return netbsd_parse_xattr_stream(jcr, stream);
1931 * Issue a warning and discard the message. But pretend the restore was ok.
1933 Qmsg2(jcr, M_WARNING, 0,
1934 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1935 jcr->last_fname, stream);
1937 } /* end switch (stream) */