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
49 #if !defined(HAVE_XATTR)
51 * Entry points when compiled without support for XATTRs or on an unsupported platform.
53 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
55 return bxattr_exit_fatal;
58 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
60 return bxattr_exit_fatal;
64 * Send a XATTR stream to the SD.
66 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
68 BSOCK *sd = jcr->store_bsock;
70 #ifdef FD_NO_SEND_TEST
71 return bxattr_exit_ok;
77 if (jcr->xattr_data->content_length <= 0) {
78 return bxattr_exit_ok;
84 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
85 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
87 return bxattr_exit_fatal;
91 * Send the buffer to the storage deamon
93 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
95 sd->msg = jcr->xattr_data->content;
96 sd->msglen = jcr->xattr_data->content_length;
100 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
102 return bxattr_exit_fatal;
105 jcr->JobBytes += sd->msglen;
107 if (!sd->signal(BNET_EOD)) {
108 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
110 return bxattr_exit_fatal;
112 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
113 return bxattr_exit_ok;
117 * This is a supported OS, See what kind of interface we should use.
118 * Start with the generic interface used by most OS-es.
120 #if defined(HAVE_DARWIN_OS) || \
121 defined(HAVE_FREEBSD_OS) || \
122 defined(HAVE_LINUX_OS) || \
123 defined(HAVE_NETBSD_OS)
125 #ifdef HAVE_SYS_XATTR_H
126 #include <sys/xattr.h>
130 * Define the supported XATTR streams for this OS
132 #if defined(HAVE_DARWIN_OS)
133 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
134 #elif defined(HAVE_FREEBSD_OS)
135 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
136 #elif defined(HAVE_LINUX_OS)
137 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
138 #elif defined(HAVE_NETBSD_OS)
139 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
143 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
144 * listxattr, getxattr and setxattr with an extra options argument
145 * which mimics the l variants of the functions when we specify
146 * XATTR_NOFOLLOW as the options value.
148 #if defined(HAVE_DARWIN_OS)
149 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
150 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
151 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
154 * Fallback to the non l-functions when those are not available.
156 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
157 #define lgetxattr getxattr
159 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
160 #define lsetxattr setxattr
162 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
163 #define llistxattr listxattr
167 static void xattr_drop_internal_table(xattr_t *xattr_value_list)
169 xattr_t *current_xattr;
172 * Walk the list of xattrs and free allocated memory on traversing.
174 for (current_xattr = xattr_value_list;
175 current_xattr != (xattr_t *)NULL;
178 * See if we can shortcut.
180 if (current_xattr->magic != XATTR_MAGIC)
183 free(current_xattr->name);
185 if (current_xattr->value_length > 0)
186 free(current_xattr->value);
190 * Free the array of control structs.
192 free(xattr_value_list);
196 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
197 * which encodes one or more xattr_t structures.
199 * The Serialized stream consists of the following elements:
200 * magic - A magic string which makes it easy to detect any binary incompatabilites
201 * name_length - The length of the following xattr name
202 * name - The name of the extended attribute
203 * value_length - The length of the following xattr data
204 * value - The actual content of the extended attribute
206 * This is repeated 1 or more times.
209 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list)
211 xattr_t *current_xattr;
215 * Make sure the serialized stream fits in the poolmem buffer.
216 * We allocate some more to be sure the stream is gonna fit.
218 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
219 ser_begin(jcr->xattr_data->content, 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->content, expected_serialize_len + 10);
240 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
241 return jcr->xattr_data->content_length;
244 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
247 int32_t xattr_list_len,
249 uint32_t expected_serialize_len = 0;
250 char *xattr_list, *bp;
251 xattr_t *xattr_value_list = NULL, *current_xattr;
252 bxattr_exit_code retval = bxattr_exit_error;
256 * First get the length of the available list with extended attributes.
258 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
259 if (xattr_list_len < 0) {
262 return bxattr_exit_ok;
264 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
265 jcr->last_fname, be.bstrerror());
266 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
267 jcr->last_fname, be.bstrerror());
268 return bxattr_exit_error;
270 } else if (xattr_list_len == 0) {
271 return bxattr_exit_ok;
275 * Allocate room for the extented attribute list.
277 xattr_list = (char *)malloc(xattr_list_len + 1);
278 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
281 * Get the actual list of extended attributes names for a file.
283 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
284 if (xattr_list_len < 0) {
287 retval = bxattr_exit_ok;
290 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
291 jcr->last_fname, be.bstrerror());
292 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
293 jcr->last_fname, be.bstrerror());
297 xattr_list[xattr_list_len] = '\0';
300 * Count the number of extended attributes on a file.
303 while ((bp - xattr_list) + 1 < xattr_list_len) {
304 #if defined(HAVE_LINUX_OS)
306 * On Linux you also get the acls in the extented attribute list.
307 * So we check if we are already backing up acls and if we do we
308 * don't store the extended attribute with the same info.
310 if ((ff_pkt->flags & FO_ACL) == 0 || strcmp(bp, "system.posix_acl_access"))
316 bp = strchr(bp, '\0') + 1;
320 retval = bxattr_exit_ok;
325 * Allocate enough room to hold all extended attributes.
326 * After allocating the storage make sure its empty by zeroing it.
328 xattr_value_list = (xattr_t *)malloc(count * sizeof(xattr_t));
329 memset((caddr_t)xattr_value_list, 0, count * sizeof(xattr_t));
332 * Walk the list of extended attributes names and retrieve the data.
333 * We already count the bytes needed for serializing the stream later on.
335 current_xattr = xattr_value_list;
337 while ((bp - xattr_list) + 1 < xattr_list_len) {
338 #if defined(HAVE_LINUX_OS)
340 * On Linux you also get the acls in the extented attribute list.
341 * So we check if we are already backing up acls and if we do we
342 * don't store the extended attribute with the same info.
344 if (ff_pkt->flags & FO_ACL && !strcmp(bp, "system.posix_acl_access")) {
345 bp = strchr(bp, '\0') + 1;
351 * Each xattr valuepair starts with a magic so we can parse it easier.
353 current_xattr->magic = XATTR_MAGIC;
354 expected_serialize_len += sizeof(current_xattr->magic);
357 * Allocate space for storing the name.
359 current_xattr->name_length = strlen(bp);
360 current_xattr->name = (char *)malloc(current_xattr->name_length);
361 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
363 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
366 * First see how long the value is for the extended attribute.
368 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
369 if (xattr_value_len < 0) {
372 retval = bxattr_exit_ok;
375 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
376 jcr->last_fname, be.bstrerror());
377 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
378 jcr->last_fname, be.bstrerror());
384 * Allocate space for storing the value.
386 current_xattr->value = (char *)malloc(xattr_value_len);
387 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
389 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
390 if (xattr_value_len < 0) {
393 retval = bxattr_exit_ok;
396 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
397 jcr->last_fname, be.bstrerror());
398 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
399 jcr->last_fname, be.bstrerror());
405 * Store the actual length of the value.
407 current_xattr->value_length = xattr_value_len;
408 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
411 * Protect ourself against things getting out of hand.
413 if (expected_serialize_len >= MAX_XATTR_STREAM) {
414 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
415 jcr->last_fname, MAX_XATTR_STREAM);
423 bp = strchr(bp, '\0') + 1;
427 * Serialize the datastream.
429 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
430 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
432 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
437 xattr_drop_internal_table(xattr_value_list);
441 * Send the datastream to the SD.
443 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
446 if (xattr_value_list) {
447 xattr_drop_internal_table(xattr_value_list);
453 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
456 xattr_t current_xattr;
457 bxattr_exit_code retval = bxattr_exit_ok;
461 * Parse the stream and perform the setxattr calls on the file.
463 * Start unserializing the data. We keep on looping while we have not
464 * unserialized all bytes in the stream.
466 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
467 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
469 * First make sure the magic is present. This way we can easily catch corruption.
470 * Any missing MAGIC is fatal we do NOT try to continue.
472 unser_uint32(current_xattr.magic);
473 if (current_xattr.magic != XATTR_MAGIC) {
474 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
476 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
478 return bxattr_exit_error;
482 * Decode the valuepair. First decode the length of the name.
484 unser_uint32(current_xattr.name_length);
487 * Allocate room for the name and decode its content.
489 current_xattr.name = (char *)malloc(current_xattr.name_length + 1);
490 unser_bytes(current_xattr.name, current_xattr.name_length);
493 * The xattr_name needs to be null terminated for lsetxattr.
495 current_xattr.name[current_xattr.name_length] = '\0';
498 * Decode the value length.
500 unser_uint32(current_xattr.value_length);
503 * Allocate room for the value and decode its content.
505 current_xattr.value = (char *)malloc(current_xattr.value_length);
506 unser_bytes(current_xattr.value, current_xattr.value_length);
509 * Try to set the extended attribute on the file.
510 * If we fail to set this attribute we flag the error but its not fatal,
511 * we try to restore the other extended attributes too.
513 if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
514 current_xattr.value_length, 0) != 0) {
519 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
520 jcr->last_fname, be.bstrerror());
521 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
522 jcr->last_fname, be.bstrerror());
523 retval = bxattr_exit_error;
529 * Free the temporary buffers.
531 free(current_xattr.name);
532 free(current_xattr.value);
535 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
540 * For all these os-es setup the build and parse function pointer to the generic functions.
542 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
543 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
545 #elif defined(HAVE_SUN_OS)
547 * Solaris extended attributes were introduced in Solaris 9
550 * Solaris extensible attributes were introduced in OpenSolaris
551 * by PSARC 2007/315 Solaris extensible attributes are also
552 * sometimes called extended system attributes.
554 * man fsattr(5) on Solaris gives a wealth of info. The most
555 * important bits are:
557 * Attributes are logically supported as files within the file
558 * system. The file system is therefore augmented with an
559 * orthogonal name space of file attributes. Any file (includ-
560 * ing attribute files) can have an arbitrarily deep attribute
561 * tree associated with it. Attribute values are accessed by
562 * file descriptors obtained through a special attribute inter-
563 * face. This logical view of "attributes as files" allows the
564 * leveraging of existing file system interface functionality
565 * to support the construction, deletion, and manipulation of
568 * The special files "." and ".." retain their accustomed
569 * semantics within the attribute hierarchy. The "." attribute
570 * file refers to the current directory and the ".." attribute
571 * file refers to the parent directory. The unnamed directory
572 * at the head of each attribute tree is considered the "child"
573 * of the file it is associated with and the ".." file refers
574 * to the associated file. For any non-directory file with
575 * attributes, the ".." entry in the unnamed directory refers
576 * to a file that is not a directory.
578 * Conceptually, the attribute model is fully general. Extended
579 * attributes can be any type of file (doors, links, direc-
580 * tories, and so forth) and can even have their own attributes
581 * (fully recursive). As a result, the attributes associated
582 * with a file could be an arbitrarily deep directory hierarchy
583 * where each attribute could have an equally complex attribute
584 * tree associated with it. Not all implementations are able
585 * to, or want to, support the full model. Implementation are
586 * therefore permitted to reject operations that are not sup-
587 * ported. For example, the implementation for the UFS file
588 * system allows only regular files as attributes (for example,
589 * no sub-directories) and rejects attempts to place attributes
592 * The following list details the operations that are rejected
593 * in the current implementation:
595 * link Any attempt to create links between
596 * attribute and non-attribute space
597 * is rejected to prevent security-
598 * related or otherwise sensitive
599 * attributes from being exposed, and
600 * therefore manipulable, as regular
603 * rename Any attempt to rename between
604 * attribute and non-attribute space
605 * is rejected to prevent an already
606 * linked file from being renamed and
607 * thereby circumventing the link res-
610 * mkdir, symlink, mknod Any attempt to create a "non-
611 * regular" file in attribute space is
612 * rejected to reduce the functional-
613 * ity, and therefore exposure and
614 * risk, of the initial implementa-
617 * The entire available name space has been allocated to "gen-
618 * eral use" to bring the implementation in line with the NFSv4
619 * draft standard [NFSv4]. That standard defines "named attri-
620 * butes" (equivalent to Solaris Extended Attributes) with no
621 * naming restrictions. All Sun applications making use of
622 * opaque extended attributes will use the prefix "SUNW".
625 #ifdef HAVE_SYS_ATTR_H
626 #include <sys/attr.h>
633 #ifdef HAVE_SYS_NVPAIR_H
634 #include <sys/nvpair.h>
637 #ifdef HAVE_SYS_ACL_H
642 * Define the supported XATTR streams for this OS
644 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
645 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
647 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
648 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
651 * This code creates a temporary cache with entries for each xattr which has
652 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
654 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
656 xattr_link_cache_entry_t *ptr;
658 foreach_alist(ptr, jcr->xattr_data->link_cache) {
659 if (ptr && ptr->inum == inum) {
666 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
668 xattr_link_cache_entry_t *ptr;
670 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
671 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
673 bstrncpy(ptr->target, target, sizeof(ptr->target));
674 jcr->xattr_data->link_cache->append(ptr);
677 static void flush_xattr_link_cache(JCR *jcr)
679 xattr_link_cache_entry_t *ptr;
681 foreach_alist(ptr, jcr->xattr_data->link_cache) {
682 if (ptr && ptr->target) {
688 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
690 * This function returns true if a non default extended system attribute
691 * list is associated with fd and returns false when an error has occured
692 * or when only extended system attributes other than archive,
693 * av_modified or crtime are set.
695 * The function returns true for the following cases:
697 * - any extended system attribute other than the default attributes
698 * ('archive', 'av_modified' and 'crtime') is set
699 * - nvlist has NULL name string
700 * - nvpair has data type of 'nvlist'
701 * - default data type.
703 static bool solaris_has_non_transient_extensible_attributes(int fd)
713 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
718 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
719 name = nvpair_name(pair);
722 fattr = name_to_attr(name);
728 type = nvpair_type(pair);
730 case DATA_TYPE_BOOLEAN_VALUE:
731 if (nvpair_value_boolean_value(pair, &value) != 0) {
734 if (value && fattr != F_ARCHIVE &&
735 fattr != F_AV_MODIFIED) {
740 case DATA_TYPE_UINT64_ARRAY:
741 if (fattr != F_CRTIME) {
746 case DATA_TYPE_NVLIST:
754 if (response != NULL) {
755 nvlist_free(response);
759 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
761 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
763 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
764 * There is no need to store those acls as we already store the stat bits too.
766 static bool acl_is_trivial(int count, aclent_t *entries)
771 for (n = 0; n < count; n++) {
773 if (!(ace->a_type == USER_OBJ ||
774 ace->a_type == GROUP_OBJ ||
775 ace->a_type == OTHER_OBJ ||
776 ace->a_type == CLASS_OBJ))
781 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
783 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
786 #ifdef HAVE_EXTENDED_ACL
792 * See if this attribute has an ACL
794 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
795 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
797 * See if there is a non trivial acl on the file.
799 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
800 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
803 return bxattr_exit_ok;
805 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
806 attrname, jcr->last_fname, be.bstrerror());
807 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
808 attrname, jcr->last_fname, be.bstrerror());
809 return bxattr_exit_error;
814 #if defined(ACL_SID_FMT)
816 * New format flag added in newer Solaris versions.
818 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
820 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
821 #endif /* ACL_SID_FMT */
823 *acl_text = acl_totext(aclp, flags);
831 return bxattr_exit_ok;
832 #else /* HAVE_EXTENDED_ACL */
834 aclent_t *acls = NULL;
838 * See if this attribute has an ACL
841 n = facl(fd, GETACLCNT, 0, NULL);
843 n = acl(attrname, GETACLCNT, 0, NULL);
846 if (n >= MIN_ACL_ENTRIES) {
847 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
848 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
849 acl(attrname, GETACL, n, acls) != n) {
853 return bxattr_exit_ok;
855 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
856 attrname, jcr->last_fname, be.bstrerror());
857 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
858 attrname, jcr->last_fname, be.bstrerror());
860 return bxattr_exit_error;
865 * See if there is a non trivial acl on the file.
867 if (!acl_is_trivial(n, acls)) {
868 if ((*acl_text = acltotext(acls, n)) == NULL) {
869 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
870 attrname, jcr->last_fname, be.bstrerror());
871 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
872 attrname, jcr->last_fname, be.bstrerror());
874 return bxattr_exit_error;
884 return bxattr_exit_ok;
885 #endif /* HAVE_EXTENDED_ACL */
888 return bxattr_exit_ok;
889 #endif /* HAVE_ACL */
893 * Forward declaration for recursive function call.
895 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
898 * Save an extended or extensible attribute.
899 * This is stored as an opaque stream of bytes with the following encoding:
901 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
903 * or for a hardlinked or symlinked attribute
905 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
907 * xattr_name can be a subpath relative to the file the xattr is on.
908 * stat_buffer is the string representation of the stat struct.
909 * acl_string is an acl text when a non trivial acl is set on the xattr.
910 * actual_xattr_data is the content of the xattr file.
912 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
913 const char *attrname, bool toplevel_hidden_dir, int stream)
918 xattr_link_cache_entry_t *xlce;
919 char target_attrname[PATH_MAX];
920 char link_source[PATH_MAX];
921 char *acl_text = NULL;
922 char attribs[MAXSTRING];
924 bxattr_exit_code retval = bxattr_exit_error;
927 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
930 * Get the stats of the extended or extensible attribute.
932 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
935 retval = bxattr_exit_ok;
938 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
939 target_attrname, jcr->last_fname, be.bstrerror());
940 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
941 target_attrname, jcr->last_fname, be.bstrerror());
947 * Based on the filetype perform the correct action. We support most filetypes here, more
948 * then the actual implementation on Solaris supports so some code may never get executed
949 * due to limitations in the implementation.
951 switch (st.st_mode & S_IFMT) {
956 * Get any acl on the xattr.
958 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
962 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
963 * Encode the stat struct into an ASCII representation.
965 encode_stat(attribs, &st, 0, stream);
966 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
967 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
971 * Get any acl on the xattr.
973 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
977 * See if this is the toplevel_hidden_dir being saved.
979 if (toplevel_hidden_dir) {
981 * Save the data for later storage when we encounter a real xattr. We store the data
982 * in the jcr->xattr_data->content buffer and flush that just before sending out the
983 * first real xattr. Encode the stat struct into an ASCII representation and jump
984 * out of the function.
986 encode_stat(attribs, &st, 0, stream);
987 cnt = bsnprintf(buffer, sizeof(buffer),
989 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
990 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
991 jcr->xattr_data->content_length = cnt;
995 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
996 * Encode the stat struct into an ASCII representation.
998 encode_stat(attribs, &st, 0, stream);
999 cnt = bsnprintf(buffer, sizeof(buffer),
1001 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1006 * If this is a hardlinked file check the inode cache for a hit.
1008 if (st.st_nlink > 1) {
1010 * See if the cache already knows this inode number.
1012 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
1014 * Generate a xattr encoding with the reference to the target in there.
1016 encode_stat(attribs, &st, st.st_ino, stream);
1017 cnt = bsnprintf(buffer, sizeof(buffer),
1019 target_attrname, 0, attribs, 0, xlce->target, 0);
1020 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1021 jcr->xattr_data->content_length = cnt;
1022 retval = send_xattr_stream(jcr, stream);
1025 * For a hard linked file we are ready now, no need to recursively save the attributes.
1031 * Store this hard linked file in the cache.
1032 * Store the name relative to the top level xattr space.
1034 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
1038 * Get any acl on the xattr.
1040 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
1045 * Encode the stat struct into an ASCII representation.
1047 encode_stat(attribs, &st, 0, stream);
1048 cnt = bsnprintf(buffer, sizeof(buffer),
1050 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1053 * Open the extended or extensible attribute file.
1055 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1058 retval = bxattr_exit_ok;
1061 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1062 target_attrname, jcr->last_fname, be.bstrerror());
1063 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1064 target_attrname, jcr->last_fname, be.bstrerror());
1071 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1072 * Encode the stat struct into an ASCII representation.
1074 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1077 retval = bxattr_exit_ok;
1080 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1081 target_attrname, jcr->last_fname, be.bstrerror());
1082 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1083 target_attrname, jcr->last_fname, be.bstrerror());
1089 * Generate a xattr encoding with the reference to the target in there.
1091 encode_stat(attribs, &st, st.st_ino, stream);
1092 cnt = bsnprintf(buffer, sizeof(buffer),
1094 target_attrname, 0, attribs, 0, link_source, 0);
1095 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1096 jcr->xattr_data->content_length = cnt;
1097 retval = send_xattr_stream(jcr, stream);
1099 if (retval == bxattr_exit_ok) {
1100 jcr->xattr_data->nr_saved++;
1104 * For a soft linked file we are ready now, no need to recursively save the attributes.
1112 * See if this is the first real xattr being saved.
1113 * If it is save the toplevel_hidden_dir attributes first.
1114 * This is easy as its stored already in the jcr->xattr_data->content buffer.
1116 if (jcr->xattr_data->nr_saved == 0) {
1117 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1118 if (retval != bxattr_exit_ok) {
1121 jcr->xattr_data->nr_saved++;
1124 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1125 jcr->xattr_data->content_length = cnt;
1128 * Only dump the content of regular files.
1130 switch (st.st_mode & S_IFMT) {
1132 if (st.st_size > 0) {
1134 * Protect ourself against things getting out of hand.
1136 if (st.st_size >= MAX_XATTR_STREAM) {
1137 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1138 jcr->last_fname, MAX_XATTR_STREAM);
1142 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1143 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
1144 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
1145 jcr->xattr_data->content_length += cnt;
1149 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
1150 target_attrname, jcr->last_fname);
1151 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1152 target_attrname, jcr->last_fname);
1163 retval = send_xattr_stream(jcr, stream);
1164 if (retval == bxattr_exit_ok) {
1165 jcr->xattr_data->nr_saved++;
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) {
1182 retval = bxattr_exit_ok;
1185 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1186 jcr->last_fname, be.bstrerror());
1187 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1188 jcr->last_fname, fd, be.bstrerror());
1204 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1207 int fd, filefd = -1, attrdirfd = -1;
1210 char current_xattr_namespace[PATH_MAX];
1211 bxattr_exit_code retval = bxattr_exit_error;
1215 * Determine what argument to use. Use attr_parent when set
1216 * (recursive call) or jcr->last_fname for first call. Also save
1217 * the current depth of the xattr_space we are in.
1221 if (xattr_namespace) {
1222 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1223 xattr_namespace, attr_parent);
1225 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1228 name = jcr->last_fname;
1229 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1233 * Open the file on which to save the xattrs read-only.
1235 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1238 retval = bxattr_exit_ok;
1241 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1242 jcr->last_fname, be.bstrerror());
1243 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1244 jcr->last_fname, be.bstrerror());
1250 * Open the xattr naming space.
1252 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1256 * Gentile way of the system saying this type of xattr layering is not supported.
1257 * Which is not problem we just forget about this this xattr.
1258 * But as this is not an error we return a positive return value.
1260 retval = bxattr_exit_ok;
1263 retval = bxattr_exit_ok;
1266 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1267 name, jcr->last_fname, be.bstrerror());
1268 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1269 name, jcr->last_fname, be.bstrerror());
1275 * We need to change into the attribute directory to determine if each of the
1276 * attributes should be saved.
1278 if (fchdir(attrdirfd) < 0) {
1279 Mmsg2(jcr->errmsg, _("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) {
1297 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1298 jcr->last_fname, be.bstrerror());
1299 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1300 jcr->last_fname, fd, be.bstrerror());
1306 * Walk the namespace.
1308 while (dp = readdir(dirp)) {
1310 * Skip only the toplevel . dir.
1312 if (!attr_parent && !strcmp(dp->d_name, "."))
1316 * Skip all .. directories
1318 if (!strcmp(dp->d_name, ".."))
1321 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1322 current_xattr_namespace, dp->d_name, jcr->last_fname);
1324 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1326 * We are not interested in read-only extensible attributes.
1328 if (!strcmp(dp->d_name, VIEW_READONLY)) {
1329 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1330 current_xattr_namespace, dp->d_name, jcr->last_fname);
1336 * We are only interested in read-write extensible attributes
1337 * when they contain non-transient values.
1339 if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1341 * Determine if there are non-transient system attributes at the toplevel.
1342 * We need to provide a fd to the open file.
1344 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1345 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1346 current_xattr_namespace, dp->d_name, jcr->last_fname);
1353 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1354 false, STREAM_XATTR_SOLARIS_SYS);
1357 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1362 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1363 false, STREAM_XATTR_SOLARIS);
1367 retval = bxattr_exit_ok;
1370 if (attrdirfd != -1)
1378 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1380 #ifdef HAVE_EXTENDED_ACL
1385 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1386 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
1388 return bxattr_exit_error;
1391 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1392 acl_set(attrname, aclp) != 0) {
1393 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1394 attrname, jcr->last_fname, be.bstrerror());
1395 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1396 attrname, jcr->last_fname, be.bstrerror());
1397 return bxattr_exit_error;
1403 return bxattr_exit_ok;
1405 #else /* HAVE_EXTENDED_ACL */
1407 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) {
1414 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1415 attrname, jcr->last_fname, be.bstrerror());
1416 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1417 attrname, jcr->last_fname, be.bstrerror());
1418 return bxattr_exit_error;
1425 return bxattr_exit_ok;
1427 #endif /* HAVE_EXTENDED_ACL */
1430 #endif /* HAVE_ACL */
1432 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1434 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1435 int used_bytes, total_bytes, cnt;
1436 char *bp, *target_attrname, *attribs;
1437 char *linked_target = NULL;
1438 char *acl_text = NULL;
1442 struct timeval times[2];
1443 bxattr_exit_code retval = bxattr_exit_error;
1447 * Parse the xattr stream. First the part that is the same for all xattrs.
1450 total_bytes = jcr->xattr_data->content_length;
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->content + 1;
1458 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1459 (used_bytes = (bp - jcr->xattr_data->content)) >= (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) {
1468 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1469 jcr->last_fname, be.bstrerror());
1470 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1471 jcr->last_fname, be.bstrerror());
1476 * Open the xattr naming space and make it the current working dir.
1478 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1479 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1480 jcr->last_fname, be.bstrerror());
1481 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1482 jcr->last_fname, be.bstrerror());
1486 if (fchdir(attrdirfd) < 0) {
1487 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1488 jcr->last_fname, be.bstrerror());
1489 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1490 jcr->last_fname, attrdirfd, be.bstrerror());
1495 * Try to open the correct xattr subdir based on the target_attrname given.
1496 * e.g. check if its a subdir attrname. Each / in the string makes us go
1499 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1502 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1503 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1504 target_attrname, jcr->last_fname, be.bstrerror());
1505 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1506 target_attrname, jcr->last_fname, be.bstrerror());
1514 * Open the xattr naming space.
1516 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1517 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1518 target_attrname, jcr->last_fname, be.bstrerror());
1519 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1520 target_attrname, jcr->last_fname, be.bstrerror());
1528 * Make the xattr space our current workingdir.
1530 if (fchdir(attrdirfd) < 0) {
1531 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1532 target_attrname, jcr->last_fname, be.bstrerror());
1533 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1534 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1538 target_attrname = ++bp;
1542 * Decode the attributes from the stream.
1544 decode_stat(attribs, &st, &inum);
1547 * Decode the next field (acl_text).
1549 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1550 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1556 * Based on the filetype perform the correct action. We support most filetypes here, more
1557 * then the actual implementation on Solaris supports so some code may never get executed
1558 * due to limitations in the implementation.
1560 switch (st.st_mode & S_IFMT) {
1563 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1565 unlinkat(attrdirfd, target_attrname, 0);
1566 if (mkfifo(target_attrname, st.st_mode) < 0) {
1567 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1568 target_attrname, jcr->last_fname, be.bstrerror());
1569 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1570 target_attrname, jcr->last_fname, be.bstrerror());
1577 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1579 unlinkat(attrdirfd, target_attrname, 0);
1580 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1581 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1582 target_attrname, jcr->last_fname, be.bstrerror());
1583 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1584 target_attrname, jcr->last_fname, be.bstrerror());
1590 * If its not the hidden_dir create the entry.
1591 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1593 if (strcmp(target_attrname, ".")) {
1594 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1595 if (mkdir(target_attrname, st.st_mode) < 0) {
1596 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1597 target_attrname, jcr->last_fname, be.bstrerror());
1598 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1599 target_attrname, jcr->last_fname, be.bstrerror());
1606 * See if this is a hard linked file. e.g. inum != 0
1611 unlinkat(attrdirfd, target_attrname, 0);
1612 if (link(linked_target, target_attrname) < 0) {
1613 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1614 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1615 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1616 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1621 * Successfully restored xattr.
1623 retval = bxattr_exit_ok;
1626 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1627 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
1631 if (used_bytes < (total_bytes - 1))
1635 * Restore the actual xattr.
1637 if (!is_extensible) {
1638 unlinkat(attrdirfd, target_attrname, 0);
1641 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1642 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1643 target_attrname, jcr->last_fname, be.bstrerror());
1644 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1645 target_attrname, jcr->last_fname, be.bstrerror());
1651 * Restore the actual data.
1653 if (st.st_size > 0) {
1654 used_bytes = (data - jcr->xattr_data->content);
1655 cnt = total_bytes - used_bytes;
1658 * Do a sanity check, the st.st_size should be the same as the number of bytes
1659 * we have available as data of the stream.
1661 if (cnt != st.st_size) {
1662 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
1663 target_attrname, jcr->last_fname);
1664 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1665 target_attrname, jcr->last_fname);
1670 cnt = write(attrfd, data, cnt);
1672 Mmsg3(jcr->errmsg, _("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) {
1692 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
1693 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1694 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
1695 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1700 * Successfully restored xattr.
1702 retval = bxattr_exit_ok;
1709 * Restore owner and acl for non extensible attributes.
1711 if (!is_extensible) {
1712 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
1716 * Gentile way of the system saying this type of xattr layering is not supported.
1717 * But as this is not an error we return a positive return value.
1719 retval = bxattr_exit_ok;
1722 retval = bxattr_exit_ok;
1725 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1726 target_attrname, jcr->last_fname, be.bstrerror());
1727 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1728 target_attrname, jcr->last_fname, be.bstrerror());
1735 if (acl_text && *acl_text)
1736 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
1738 #endif /* HAVE_ACL */
1741 * For a non extensible attribute restore access and modification time on the xattr.
1743 if (!is_extensible) {
1744 times[0].tv_sec = st.st_atime;
1745 times[0].tv_usec = 0;
1746 times[1].tv_sec = st.st_mtime;
1747 times[1].tv_usec = 0;
1749 if (futimesat(attrdirfd, target_attrname, times) < 0) {
1750 Mmsg3(jcr->errmsg, _("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.
1761 retval = bxattr_exit_ok;
1765 Mmsg1(jcr->errmsg, _("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 bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1786 bxattr_exit_code retval = bxattr_exit_ok;
1789 * First see if extended attributes or extensible attributes are present.
1790 * If not just pretend things went ok.
1792 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1793 jcr->xattr_data->nr_saved = 0;
1794 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
1797 * As we change the cwd in the save function save the current cwd
1798 * for restore after return from the solaris_save_xattrs function.
1800 getcwd(cwd, sizeof(cwd));
1801 retval = solaris_save_xattrs(jcr, NULL, NULL);
1803 flush_xattr_link_cache(jcr);
1804 delete jcr->xattr_data->link_cache;
1805 jcr->xattr_data->link_cache = NULL;
1810 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
1813 bool is_extensible = false;
1814 bxattr_exit_code retval;
1817 * First make sure we can restore xattr on the filesystem.
1820 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1821 case STREAM_XATTR_SOLARIS_SYS:
1822 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1823 Qmsg1(jcr, M_WARNING, 0,
1824 _("Failed to restore extensible attributes on file \"%s\"\n"),
1826 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1828 return bxattr_exit_error;
1831 is_extensible = true;
1834 case STREAM_XATTR_SOLARIS:
1835 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1836 Qmsg1(jcr, M_WARNING, 0,
1837 _("Failed to restore extended attributes on file \"%s\"\n"),
1839 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1841 return bxattr_exit_error;
1845 return bxattr_exit_error;
1849 * As we change the cwd in the restore function save the current cwd
1850 * for restore after return from the solaris_restore_xattrs function.
1852 getcwd(cwd, sizeof(cwd));
1853 retval = solaris_restore_xattrs(jcr, is_extensible);
1860 * Function pointers to the build and parse function to use for these xattrs.
1862 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
1863 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
1865 #endif /* defined(HAVE_SUN_OS) */
1868 * Entry points when compiled with support for XATTRs on a supported platform.
1870 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1872 if (os_build_xattr_streams) {
1873 return (*os_build_xattr_streams)(jcr, ff_pkt);
1875 return bxattr_exit_error;
1878 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
1882 if (os_parse_xattr_streams) {
1884 * See if we can parse this stream, and ifso give it a try.
1886 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
1887 if (os_default_xattr_streams[cnt] == stream) {
1888 return (*os_parse_xattr_streams)(jcr, stream);
1893 * Issue a warning and discard the message. But pretend the restore was ok.
1895 Jmsg2(jcr, M_WARNING, 0,
1896 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1897 jcr->last_fname, stream);
1898 return bxattr_exit_error;