2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2009 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Functions to handle Extended Attributes for bacula.
31 * Extended Attributes are so OS specific we only restore Extended Attributes if
32 * they were saved using a filed on the same platform.
34 * Currently we support the following OSes:
35 * - FreeBSD (Extended Attributes)
36 * - Darwin (Extended Attributes)
37 * - Linux (Extended Attributes)
38 * - NetBSD (Extended Attributes)
39 * - Solaris (Extended Attributes and Extensible Attributes)
41 * Written by Marco van Wieringen, November MMVIII
50 #if !defined(HAVE_XATTR)
52 * Entry points when compiled without support for XATTRs or on an unsupported platform.
54 bsub_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
56 return bsub_exit_fatal;
59 bsub_exit_code parse_xattr_streams(JCR *jcr, int stream)
61 return bsub_exit_fatal;
65 * Send a XATTR stream to the SD.
67 static bsub_exit_code send_xattr_stream(JCR *jcr, int stream)
69 BSOCK *sd = jcr->store_bsock;
71 #ifdef FD_NO_SEND_TEST
78 if (jcr->xattr_data_len <= 0)
84 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
85 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
87 return bsub_exit_fatal;
91 * Send the buffer to the storage deamon
93 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data);
95 sd->msg = jcr->xattr_data;
96 sd->msglen = jcr->xattr_data_len;
100 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
102 return bsub_exit_fatal;
105 jcr->JobBytes += sd->msglen;
107 if (!sd->signal(BNET_EOD)) {
108 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
110 return bsub_exit_fatal;
112 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
117 * This is a supported OS, See what kind of interface we should use.
118 * Start with the generic interface used by most OS-es.
120 #if defined(HAVE_DARWIN_OS) \
121 || defined(HAVE_FREEBSD_OS) \
122 || defined(HAVE_LINUX_OS) \
123 || defined(HAVE_NETBSD_OS)
125 #ifdef HAVE_SYS_XATTR_H
126 #include <sys/xattr.h>
130 * All these os-es have 1 xattr stream.
132 #if defined(HAVE_DARWIN_OS)
133 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
134 #elif defined(HAVE_FREEBSD_OS)
135 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
136 #elif defined(HAVE_LINUX_OS)
137 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
138 #elif defined(HAVE_NETBSD_OS)
139 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
143 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
144 * listxattr, getxattr and setxattr with an extra options argument
145 * which mimics the l variants of the functions when we specify
146 * XATTR_NOFOLLOW as the options value.
148 #if defined(HAVE_DARWIN_OS)
149 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
150 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
151 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
154 * Fallback to the non l-functions when those are not available.
156 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
157 #define lgetxattr getxattr
159 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
160 #define lsetxattr setxattr
162 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
163 #define llistxattr listxattr
167 static void xattr_drop_internal_table(xattr_t *xattr_value_list)
169 xattr_t *current_xattr;
172 * Walk the list of xattrs and free allocated memory on traversing.
174 for (current_xattr = xattr_value_list;
175 current_xattr != (xattr_t *)NULL;
178 * See if we can shortcut.
180 if (current_xattr->magic != XATTR_MAGIC)
183 free(current_xattr->name);
185 if (current_xattr->value_length > 0)
186 free(current_xattr->value);
190 * Free the array of control structs.
192 free(xattr_value_list);
196 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
197 * which encodes one or more xattr_t structures.
199 * The Serialized stream consists of the following elements:
200 * magic - A magic string which makes it easy to detect any binary incompatabilites
201 * name_length - The length of the following xattr name
202 * name - The name of the extended attribute
203 * value_length - The length of the following xattr data
204 * value - The actual content of the extended attribute
206 * This is repeated 1 or more times.
209 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list)
211 xattr_t *current_xattr;
215 * Make sure the serialized stream fits in the poolmem buffer.
216 * We allocate some more to be sure the stream is gonna fit.
218 jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, expected_serialize_len + 10);
219 ser_begin(jcr->xattr_data, expected_serialize_len + 10);
222 * Walk the list of xattrs and serialize the data.
224 for (current_xattr = xattr_value_list; current_xattr != (xattr_t *)NULL; current_xattr++) {
226 * See if we can shortcut.
228 if (current_xattr->magic != XATTR_MAGIC)
231 ser_uint32(current_xattr->magic);
232 ser_uint32(current_xattr->name_length);
233 ser_bytes(current_xattr->name, current_xattr->name_length);
235 ser_uint32(current_xattr->value_length);
236 ser_bytes(current_xattr->value, current_xattr->value_length);
239 ser_end(jcr->xattr_data, expected_serialize_len + 10);
240 jcr->xattr_data_len = ser_length(jcr->xattr_data);
241 return jcr->xattr_data_len;
244 static bsub_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int default_stream)
247 int32_t xattr_list_len,
249 uint32_t expected_serialize_len = 0;
250 char *xattr_list, *bp;
251 xattr_t *xattr_value_list, *current_xattr;
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) {
261 return bsub_exit_nok;
263 Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
264 jcr->last_fname, be.bstrerror());
265 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
266 jcr->last_fname, be.bstrerror());
267 return bsub_exit_nok;
269 } else if (xattr_list_len == 0) {
274 * Allocate room for the extented attribute list.
276 xattr_list = (char *)malloc(xattr_list_len + 1);
277 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
280 * Get the actual list of extended attributes names for a file.
282 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
283 if (xattr_list_len < 0) {
287 return bsub_exit_nok;
289 Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
290 jcr->last_fname, be.bstrerror());
291 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
292 jcr->last_fname, be.bstrerror());
294 return bsub_exit_nok;
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;
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)
339 if (ff_pkt->flags & FO_ACL && !strcmp(bp, "system.posix_acl_access")) {
340 bp = strchr(bp, '\0') + 1;
346 * Each xattr valuepair starts with a magic so we can parse it easier.
348 current_xattr->magic = XATTR_MAGIC;
349 expected_serialize_len += sizeof(current_xattr->magic);
352 * Allocate space for storing the name.
354 current_xattr->name_length = strlen(bp);
355 current_xattr->name = (char *)malloc(current_xattr->name_length);
356 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
358 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
361 * First see how long the value is for the extended attribute.
363 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
364 if (xattr_value_len < 0) {
369 Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
370 jcr->last_fname, be.bstrerror());
371 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
372 jcr->last_fname, be.bstrerror());
378 * Allocate space for storing the value.
380 current_xattr->value = (char *)malloc(xattr_value_len);
381 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
383 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
384 if (xattr_value_len < 0) {
389 Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
390 jcr->last_fname, be.bstrerror());
391 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
392 jcr->last_fname, be.bstrerror());
398 * Store the actual length of the value.
400 current_xattr->value_length = xattr_value_len;
401 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
404 * Protect ourself against things getting out of hand.
406 if (expected_serialize_len >= MAX_XATTR_STREAM) {
407 Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
408 jcr->last_fname, MAX_XATTR_STREAM);
416 bp = strchr(bp, '\0') + 1;
420 * Serialize the datastream.
422 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
423 Jmsg1(jcr, M_ERROR, 0, _("Failed to serialize extended attributes on file \"%s\"\n"),
425 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
430 xattr_drop_internal_table(xattr_value_list);
434 * Send the datastream to the SD.
436 return send_xattr_stream(jcr, default_stream);
439 xattr_drop_internal_table(xattr_value_list);
441 return bsub_exit_nok;
444 static bsub_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
447 xattr_t current_xattr;
448 bsub_exit_code retval = bsub_exit_nok;
452 * Parse the stream and perform the setxattr calls on the file.
454 * Start unserializing the data. We keep on looping while we have not
455 * unserialized all bytes in the stream.
457 unser_begin(jcr->xattr_data, jcr->xattr_data_len);
458 while (unser_length(jcr->xattr_data) < jcr->xattr_data_len) {
460 * First make sure the magic is present. This way we can easily catch corruption.
461 * Any missing MAGIC is fatal we do NOT try to continue.
463 unser_uint32(current_xattr.magic);
464 if (current_xattr.magic != XATTR_MAGIC) {
465 Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
467 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
469 return bsub_exit_nok;
473 * Decode the valuepair. First decode the length of the name.
475 unser_uint32(current_xattr.name_length);
478 * Allocate room for the name and decode its content.
480 current_xattr.name = (char *)malloc(current_xattr.name_length + 1);
481 unser_bytes(current_xattr.name, current_xattr.name_length);
484 * The xattr_name needs to be null terminated for lsetxattr.
486 current_xattr.name[current_xattr.name_length] = '\0';
489 * Decode the value length.
491 unser_uint32(current_xattr.value_length);
494 * Allocate room for the value and decode its content.
496 current_xattr.value = (char *)malloc(current_xattr.value_length);
497 unser_bytes(current_xattr.value, current_xattr.value_length);
500 * Try to set the extended attribute on the file.
501 * If we fail to set this attribute we flag the error but its not fatal,
502 * we try to restore the other extended attributes too.
504 if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
509 current_xattr.value_length, 0) != 0) {
510 Jmsg2(jcr, M_ERROR, 0, _("lsetxattr error on file \"%s\": ERR=%s\n"),
511 jcr->last_fname, be.bstrerror());
512 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
513 jcr->last_fname, be.bstrerror());
519 * Free the temporary buffers.
521 free(current_xattr.name);
522 free(current_xattr.value);
525 unser_end(jcr->xattr_data, jcr->xattr_data_len);
530 * For all these os-es setup the build and parse function pointer to the generic functions.
532 static bsub_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt, int default_stream) = generic_xattr_build_streams;
533 static bsub_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
535 #elif defined(HAVE_SUN_OS)
537 * Solaris extended attributes were introduced in Solaris 9
540 * Solaris extensible attributes were introduced in OpenSolaris
541 * by PSARC 2007/315 Solaris extensible attributes are also
542 * sometimes called extended system attributes.
544 * man fsattr(5) on Solaris gives a wealth of info. The most
545 * important bits are:
547 * Attributes are logically supported as files within the file
548 * system. The file system is therefore augmented with an
549 * orthogonal name space of file attributes. Any file (includ-
550 * ing attribute files) can have an arbitrarily deep attribute
551 * tree associated with it. Attribute values are accessed by
552 * file descriptors obtained through a special attribute inter-
553 * face. This logical view of "attributes as files" allows the
554 * leveraging of existing file system interface functionality
555 * to support the construction, deletion, and manipulation of
558 * The special files "." and ".." retain their accustomed
559 * semantics within the attribute hierarchy. The "." attribute
560 * file refers to the current directory and the ".." attribute
561 * file refers to the parent directory. The unnamed directory
562 * at the head of each attribute tree is considered the "child"
563 * of the file it is associated with and the ".." file refers
564 * to the associated file. For any non-directory file with
565 * attributes, the ".." entry in the unnamed directory refers
566 * to a file that is not a directory.
568 * Conceptually, the attribute model is fully general. Extended
569 * attributes can be any type of file (doors, links, direc-
570 * tories, and so forth) and can even have their own attributes
571 * (fully recursive). As a result, the attributes associated
572 * with a file could be an arbitrarily deep directory hierarchy
573 * where each attribute could have an equally complex attribute
574 * tree associated with it. Not all implementations are able
575 * to, or want to, support the full model. Implementation are
576 * therefore permitted to reject operations that are not sup-
577 * ported. For example, the implementation for the UFS file
578 * system allows only regular files as attributes (for example,
579 * no sub-directories) and rejects attempts to place attributes
582 * The following list details the operations that are rejected
583 * in the current implementation:
585 * link Any attempt to create links between
586 * attribute and non-attribute space
587 * is rejected to prevent security-
588 * related or otherwise sensitive
589 * attributes from being exposed, and
590 * therefore manipulable, as regular
593 * rename Any attempt to rename between
594 * attribute and non-attribute space
595 * is rejected to prevent an already
596 * linked file from being renamed and
597 * thereby circumventing the link res-
600 * mkdir, symlink, mknod Any attempt to create a "non-
601 * regular" file in attribute space is
602 * rejected to reduce the functional-
603 * ity, and therefore exposure and
604 * risk, of the initial implementa-
607 * The entire available name space has been allocated to "gen-
608 * eral use" to bring the implementation in line with the NFSv4
609 * draft standard [NFSv4]. That standard defines "named attri-
610 * butes" (equivalent to Solaris Extended Attributes) with no
611 * naming restrictions. All Sun applications making use of
612 * opaque extended attributes will use the prefix "SUNW".
615 #ifdef HAVE_SYS_ATTR_H
616 #include <sys/attr.h>
623 #ifdef HAVE_SYS_NVPAIR_H
624 #include <sys/nvpair.h>
627 #ifdef HAVE_SYS_ACL_H
632 * Number of xattr streams this OS supports and an array with integers with the actual stream numbers.
634 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
635 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
637 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
638 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
641 * This is the count of xattrs saved on a certain file, it gets reset
642 * on each new file processed and is used to see if we need to send
643 * the hidden xattr dir data. We only send that data when we encounter
644 * an other xattr on the file.
646 static int nr_xattr_saved = 0;
647 static char toplevel_hidden_dir_xattr_data[MAXSTRING];
648 static int toplevel_hidden_dir_xattr_data_len;
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 alist *xattr_link_cache = NULL;
656 static struct xattr_link_cache_entry *find_xattr_link_cache_entry(ino_t inum)
658 xattr_link_cache_entry_t *ptr;
660 foreach_alist(ptr, xattr_link_cache) {
661 if (ptr && ptr->inum == inum) {
668 static void add_xattr_link_cache_entry(ino_t inum, char *target)
670 xattr_link_cache_entry_t *ptr;
672 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(struct xattr_link_cache_entry));
673 memset((caddr_t)ptr, 0, sizeof(struct xattr_link_cache_entry));
675 strncpy(ptr->target, target, sizeof(ptr->target));
676 xattr_link_cache->append(ptr);
679 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
681 * This function returns true if a non default extended system attribute
682 * list is associated with fd and returns false when an error has occured
683 * or when only extended system attributes other than archive,
684 * av_modified or crtime are set.
686 * The function returns true for the following cases:
688 * - any extended system attribute other than the default attributes
689 * ('archive', 'av_modified' and 'crtime') is set
690 * - nvlist has NULL name string
691 * - nvpair has data type of 'nvlist'
692 * - default data type.
694 static bool solaris_has_non_transient_extensible_attributes(int fd)
704 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
709 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
710 name = nvpair_name(pair);
713 fattr = name_to_attr(name);
719 type = nvpair_type(pair);
721 case DATA_TYPE_BOOLEAN_VALUE:
722 if (nvpair_value_boolean_value(pair, &value) != 0) {
725 if (value && fattr != F_ARCHIVE &&
726 fattr != F_AV_MODIFIED) {
731 case DATA_TYPE_UINT64_ARRAY:
732 if (fattr != F_CRTIME) {
737 case DATA_TYPE_NVLIST:
745 if (response != NULL) {
746 nvlist_free(response);
750 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
752 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
754 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
755 * There is no need to store those acls as we already store the stat bits too.
757 static bool acl_is_trivial(int count, aclent_t *entries)
762 for (n = 0; n < count; n++) {
764 if (!(ace->a_type == USER_OBJ ||
765 ace->a_type == GROUP_OBJ ||
766 ace->a_type == OTHER_OBJ ||
767 ace->a_type == CLASS_OBJ))
772 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
774 static bsub_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
777 #ifdef HAVE_EXTENDED_ACL
783 * See if this attribute has an ACL
785 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
786 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
788 * See if there is a non trivial acl on the file.
790 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
791 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
794 return bsub_exit_nok;
796 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
797 attrname, jcr->last_fname, be.bstrerror());
798 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
799 attrname, jcr->last_fname, be.bstrerror());
800 return bsub_exit_nok;
805 #if defined(ACL_SID_FMT)
807 * New format flag added in newer Solaris versions.
809 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
811 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
812 #endif /* ACL_SID_FMT */
814 *acl_text = acl_totext(aclp, flags);
823 #else /* HAVE_EXTENDED_ACL */
825 aclent_t *acls = NULL;
829 * See if this attribute has an ACL
832 n = facl(fd, GETACLCNT, 0, NULL);
834 n = acl(attrname, GETACLCNT, 0, NULL);
837 if (n >= MIN_ACL_ENTRIES) {
838 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
839 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
840 acl(attrname, GETACL, n, acls) != n) {
844 return bsub_exit_nok;
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/acl of xattr %s on \"%s\" failed: ERR=%s\n",
849 attrname, jcr->last_fname, be.bstrerror());
851 return bsub_exit_nok;
856 * See if there is a non trivial acl on the file.
858 if (!acl_is_trivial(n, acls)) {
859 if ((*acl_text = acltotext(acls, n)) == NULL) {
860 Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
861 attrname, jcr->last_fname, be.bstrerror());
862 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
863 attrname, jcr->last_fname, be.bstrerror());
865 return bsub_exit_nok;
876 #endif /* HAVE_EXTENDED_ACL */
880 #endif /* HAVE_ACL */
884 * Forward declaration for recursive function call.
886 static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
889 * Save an extended or extensible attribute.
890 * This is stored as an opaque stream of bytes with the following encoding:
892 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
894 * or for a hardlinked or symlinked attribute
896 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
898 * xattr_name can be a subpath relative to the file the xattr is on.
899 * stat_buffer is the string representation of the stat struct.
900 * acl_string is an acl text when a non trivial acl is set on the xattr.
901 * actual_xattr_data is the content of the xattr file.
903 static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
904 const char *attrname, bool toplevel_hidden_dir, int stream)
909 struct xattr_link_cache_entry *xlce;
910 char target_attrname[PATH_MAX];
911 char link_source[PATH_MAX];
912 char *acl_text = NULL;
913 char attribs[MAXSTRING];
915 bsub_exit_code retval = bsub_exit_nok;
918 snprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
921 * Get the stats of the extended or extensible attribute.
923 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
928 Jmsg3(jcr, M_ERROR, 0, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
929 target_attrname, jcr->last_fname, be.bstrerror());
930 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
931 target_attrname, jcr->last_fname, be.bstrerror());
937 * Based on the filetype perform the correct action. We support most filetypes here, more
938 * then the actual implementation on Solaris supports so some code may never get executed
939 * due to limitations in the implementation.
941 switch (st.st_mode & S_IFMT) {
946 * Get any acl on the xattr.
948 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok)
952 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
953 * Encode the stat struct into an ASCII representation.
955 encode_stat(attribs, &st, 0, stream);
956 cnt = snprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
957 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
962 * Get any acl on the xattr.
964 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok)
968 * See if this is the toplevel_hidden_dir being saved.
970 if (toplevel_hidden_dir) {
972 * Save the data for later storage when we encounter a real xattr.
973 * Encode the stat struct into an ASCII representation and jump out of the function.
975 encode_stat(attribs, &st, 0, stream);
976 toplevel_hidden_dir_xattr_data_len = snprintf(toplevel_hidden_dir_xattr_data,
977 sizeof(toplevel_hidden_dir_xattr_data),
979 target_attrname, 0, attribs, 0,
980 (acl_text) ? acl_text : "", 0);
984 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
985 * Encode the stat struct into an ASCII representation.
987 encode_stat(attribs, &st, 0, stream);
988 cnt = snprintf(buffer, sizeof(buffer),
990 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
995 * If this is a hardlinked file check the inode cache for a hit.
997 if (st.st_nlink > 1) {
999 * See if the cache already knows this inode number.
1001 if ((xlce = find_xattr_link_cache_entry(st.st_ino)) != NULL) {
1003 * Generate a xattr encoding with the reference to the target in there.
1005 encode_stat(attribs, &st, st.st_ino, stream);
1006 cnt = snprintf(buffer, sizeof(buffer),
1008 target_attrname, 0, attribs, 0, xlce->target, 0);
1009 pm_memcpy(jcr->xattr_data, buffer, cnt);
1010 jcr->xattr_data_len = cnt;
1011 retval = send_xattr_stream(jcr, stream);
1014 * For a hard linked file we are ready now, no need to recursively save the attributes.
1020 * Store this hard linked file in the cache.
1021 * Store the name relative to the top level xattr space.
1023 add_xattr_link_cache_entry(st.st_ino, target_attrname + 1);
1027 * Get any acl on the xattr.
1029 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok) {
1034 * Encode the stat struct into an ASCII representation.
1036 encode_stat(attribs, &st, 0, stream);
1037 cnt = snprintf(buffer, sizeof(buffer),
1039 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1042 * Open the extended or extensible attribute file.
1044 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1049 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1050 target_attrname, jcr->last_fname, be.bstrerror());
1051 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1052 target_attrname, jcr->last_fname, be.bstrerror());
1060 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1061 * Encode the stat struct into an ASCII representation.
1063 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1068 Jmsg3(jcr, M_ERROR, 0, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1069 target_attrname, jcr->last_fname, be.bstrerror());
1070 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1071 target_attrname, jcr->last_fname, be.bstrerror());
1077 * Generate a xattr encoding with the reference to the target in there.
1079 encode_stat(attribs, &st, st.st_ino, stream);
1080 cnt = snprintf(buffer, sizeof(buffer),
1082 target_attrname, 0, attribs, 0, link_source, 0);
1083 pm_memcpy(jcr->xattr_data, buffer, cnt);
1084 jcr->xattr_data_len = cnt;
1085 retval = send_xattr_stream(jcr, stream);
1088 * For a soft linked file we are ready now, no need to recursively save the attributes.
1097 * See if this is the first real xattr being saved. If it is save the toplevel_hidden_dir attributes first.
1099 if (nr_xattr_saved == 0) {
1100 pm_memcpy(jcr->xattr_data, toplevel_hidden_dir_xattr_data, toplevel_hidden_dir_xattr_data_len);
1101 jcr->xattr_data_len = toplevel_hidden_dir_xattr_data_len;
1102 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1105 pm_memcpy(jcr->xattr_data, buffer, cnt);
1106 jcr->xattr_data_len = cnt;
1109 * Only dump the content of regular files.
1111 switch (st.st_mode & S_IFMT) {
1113 if (st.st_size > 0) {
1115 * Protect ourself against things getting out of hand.
1117 if (st.st_size >= MAX_XATTR_STREAM) {
1118 Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1119 jcr->last_fname, MAX_XATTR_STREAM);
1123 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1124 jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, jcr->xattr_data_len + cnt);
1125 memcpy(jcr->xattr_data + jcr->xattr_data_len, buffer, cnt);
1126 jcr->xattr_data_len += cnt;
1130 Jmsg2(jcr, M_ERROR, 0, _("Unable to read content of xattr %s on file \"%s\"\n"),
1131 target_attrname, jcr->last_fname);
1132 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1133 target_attrname, jcr->last_fname);
1144 retval = send_xattr_stream(jcr, stream);
1149 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1150 * available on this extended attribute.
1153 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1156 * The recursive call could change our working dir so change back to the wanted workdir.
1158 if (fchdir(fd) < 0) {
1163 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1164 jcr->last_fname, be.bstrerror());
1165 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1166 jcr->last_fname, fd, be.bstrerror());
1182 static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1185 int fd, filefd = -1, attrdirfd = -1;
1188 char current_xattr_namespace[PATH_MAX];
1189 bsub_exit_code retval = bsub_exit_nok;
1193 * Determine what argument to use. Use attr_parent when set
1194 * (recursive call) or jcr->last_fname for first call. Also save
1195 * the current depth of the xattr_space we are in.
1199 if (xattr_namespace) {
1200 snprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1201 xattr_namespace, attr_parent);
1203 strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1206 name = jcr->last_fname;
1207 strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1211 * Open the file on which to save the xattrs read-only.
1213 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1218 Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1219 jcr->last_fname, be.bstrerror());
1220 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1221 jcr->last_fname, be.bstrerror());
1227 * Open the xattr naming space.
1229 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1233 * Gentile way of the system saying this type of xattr layering is not supported.
1234 * Which is not problem we just forget about this this xattr.
1235 * But as this is not an error we return a positive return value.
1237 retval = bsub_exit_ok;
1242 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1243 name, jcr->last_fname, be.bstrerror());
1244 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1245 name, jcr->last_fname, be.bstrerror());
1251 * We need to change into the attribute directory to determine if each of the
1252 * attributes should be saved.
1254 if (fchdir(attrdirfd) < 0) {
1255 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1256 jcr->last_fname, be.bstrerror());
1257 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1258 jcr->last_fname, attrdirfd, be.bstrerror());
1263 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1264 * else because the readdir returns "." entry after the extensible attr entry.
1265 * And as we want this entry before anything else we better just save its data.
1268 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1269 true, STREAM_XATTR_SOLARIS);
1271 if ((fd = dup(attrdirfd)) == -1 ||
1272 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1273 Jmsg2(jcr, M_ERROR, 0, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1274 jcr->last_fname, be.bstrerror());
1275 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1276 jcr->last_fname, fd, be.bstrerror());
1282 * Walk the namespace.
1284 while (dp = readdir(dirp)) {
1286 * Skip only the toplevel . dir.
1288 if (!attr_parent && !strcmp(dp->d_name, "."))
1292 * Skip all .. directories
1294 if (!strcmp(dp->d_name, ".."))
1297 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1298 current_xattr_namespace, dp->d_name, jcr->last_fname);
1300 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1302 * We are not interested in read-only extensible attributes.
1304 if (!strcmp(dp->d_name, VIEW_READONLY)) {
1305 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1306 current_xattr_namespace, dp->d_name, jcr->last_fname);
1312 * We are only interested in read-write extensible attributes
1313 * when they contain non-transient values.
1315 if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1317 * Determine if there are non-transient system attributes at the toplevel.
1318 * We need to provide a fd to the open file.
1320 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1321 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1322 current_xattr_namespace, dp->d_name, jcr->last_fname);
1329 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1330 false, STREAM_XATTR_SOLARIS_SYS);
1333 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1338 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1339 false, STREAM_XATTR_SOLARIS);
1343 retval = bsub_exit_ok;
1346 if (attrdirfd != -1)
1354 static bsub_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1356 #ifdef HAVE_EXTENDED_ACL
1361 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1362 Jmsg1(jcr, M_ERROR, 0, _("Unable to convert acl from text on file \"%s\"\n"),
1364 return bsub_exit_nok;
1367 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1368 acl_set(attrname, aclp) != 0) {
1369 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1370 attrname, jcr->last_fname, be.bstrerror());
1371 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1372 attrname, jcr->last_fname, be.bstrerror());
1373 return bsub_exit_nok;
1379 return bsub_exit_ok;
1381 #else /* HAVE_EXTENDED_ACL */
1383 aclent_t *acls = NULL;
1386 acls = aclfromtext(acl_text, &n);
1388 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1389 acl(attrname, SETACL, n, acls) != 0) {
1390 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1391 attrname, jcr->last_fname, be.bstrerror());
1392 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1393 attrname, jcr->last_fname, be.bstrerror());
1394 return bsub_exit_nok;
1401 return bsub_exit_ok;
1403 #endif /* HAVE_EXTENDED_ACL */
1406 #endif /* HAVE_ACL */
1408 static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1410 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1411 int used_bytes, total_bytes, cnt;
1412 char *bp, *target_attrname, *attribs;
1413 char *linked_target = NULL;
1414 char *acl_text = NULL;
1418 struct timeval times[2];
1419 bsub_exit_code retval = bsub_exit_nok;
1423 * Parse the xattr stream. First the part that is the same for all xattrs.
1426 total_bytes = jcr->xattr_data_len;
1429 * The name of the target xattr has a leading / we are not interested
1430 * in that so skip it when decoding the string. We always start a the /
1431 * of the xattr space anyway.
1433 target_attrname = jcr->xattr_data + 1;
1434 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1435 (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1441 * Open the file on which to restore the xattrs read-only.
1443 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1444 Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
1445 jcr->last_fname, be.bstrerror());
1446 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1447 jcr->last_fname, be.bstrerror());
1452 * Open the xattr naming space and make it the current working dir.
1454 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1455 Jmsg2(jcr, M_ERROR, 0, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1456 jcr->last_fname, be.bstrerror());
1457 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1458 jcr->last_fname, be.bstrerror());
1462 if (fchdir(attrdirfd) < 0) {
1463 Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1464 jcr->last_fname, be.bstrerror());
1465 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1466 jcr->last_fname, attrdirfd, be.bstrerror());
1471 * Try to open the correct xattr subdir based on the target_attrname given.
1472 * e.g. check if its a subdir attrname. Each / in the string makes us go
1475 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1478 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1479 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1480 target_attrname, jcr->last_fname, be.bstrerror());
1481 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1482 target_attrname, jcr->last_fname, be.bstrerror());
1490 * Open the xattr naming space.
1492 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1493 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1494 target_attrname, jcr->last_fname, be.bstrerror());
1495 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1496 target_attrname, jcr->last_fname, be.bstrerror());
1504 * Make the xattr space our current workingdir.
1506 if (fchdir(attrdirfd) < 0) {
1507 Jmsg3(jcr, M_ERROR, 0, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1508 target_attrname, jcr->last_fname, be.bstrerror());
1509 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1510 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1514 target_attrname = ++bp;
1518 * Decode the attributes from the stream.
1520 decode_stat(attribs, &st, &inum);
1523 * Decode the next field (acl_text).
1525 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1526 (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
1532 * Based on the filetype perform the correct action. We support most filetypes here, more
1533 * then the actual implementation on Solaris supports so some code may never get executed
1534 * due to limitations in the implementation.
1536 switch (st.st_mode & S_IFMT) {
1539 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1541 unlinkat(attrdirfd, target_attrname, 0);
1542 if (mkfifo(target_attrname, st.st_mode) < 0) {
1543 Jmsg3(jcr, M_ERROR, 0, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1544 target_attrname, jcr->last_fname, be.bstrerror());
1545 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1546 target_attrname, jcr->last_fname, be.bstrerror());
1553 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1555 unlinkat(attrdirfd, target_attrname, 0);
1556 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1557 Jmsg3(jcr, M_ERROR, 0, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1558 target_attrname, jcr->last_fname, be.bstrerror());
1559 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1560 target_attrname, jcr->last_fname, be.bstrerror());
1566 * If its not the hidden_dir create the entry.
1567 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1569 if (strcmp(target_attrname, ".")) {
1570 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1571 if (mkdir(target_attrname, st.st_mode) < 0) {
1572 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1573 target_attrname, jcr->last_fname, be.bstrerror());
1574 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1575 target_attrname, jcr->last_fname, be.bstrerror());
1582 * See if this is a hard linked file. e.g. inum != 0
1587 unlinkat(attrdirfd, target_attrname, 0);
1588 if (link(linked_target, target_attrname) < 0) {
1589 Jmsg4(jcr, M_ERROR, 0, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1590 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1591 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1592 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1597 * Successfully restored xattr.
1599 retval = bsub_exit_ok;
1602 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1603 (used_bytes = (bp - jcr->xattr_data)) >= total_bytes) {
1607 if (used_bytes < (total_bytes - 1))
1611 * Restore the actual xattr.
1613 if (!is_extensible) {
1614 unlinkat(attrdirfd, target_attrname, 0);
1617 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1618 Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1619 target_attrname, jcr->last_fname, be.bstrerror());
1620 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1621 target_attrname, jcr->last_fname, be.bstrerror());
1627 * Restore the actual data.
1629 if (st.st_size > 0) {
1630 used_bytes = (data - jcr->xattr_data);
1631 cnt = total_bytes - used_bytes;
1634 * Do a sanity check, the st.st_size should be the same as the number of bytes
1635 * we have available as data of the stream.
1637 if (cnt != st.st_size) {
1638 Jmsg2(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
1639 target_attrname, jcr->last_fname);
1640 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1641 target_attrname, jcr->last_fname);
1646 cnt = write(attrfd, data, cnt);
1648 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
1649 target_attrname, jcr->last_fname, be.bstrerror());
1650 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
1651 target_attrname, jcr->last_fname, be.bstrerror());
1657 cnt = total_bytes - used_bytes;
1663 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1667 if (symlink(linked_target, target_attrname) < 0) {
1668 Jmsg4(jcr, M_ERROR, 0, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
1669 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1670 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
1671 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1676 * Successfully restored xattr.
1678 retval = bsub_exit_ok;
1685 * Restore owner and acl for non extensible attributes.
1687 if (!is_extensible) {
1688 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
1692 * Gentile way of the system saying this type of xattr layering is not supported.
1693 * But as this is not an error we return a positive return value.
1695 retval = bsub_exit_ok;
1698 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1699 target_attrname, jcr->last_fname, be.bstrerror());
1700 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1701 target_attrname, jcr->last_fname, be.bstrerror());
1708 if (acl_text && *acl_text)
1709 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bsub_exit_ok)
1711 #endif /* HAVE_ACL */
1714 * For a non extensible attribute restore access and modification time on the xattr.
1716 if (!is_extensible) {
1717 times[0].tv_sec = st.st_atime;
1718 times[0].tv_usec = 0;
1719 times[1].tv_sec = st.st_mtime;
1720 times[1].tv_usec = 0;
1722 if (futimesat(attrdirfd, target_attrname, times) < 0) {
1723 Jmsg3(jcr, M_ERROR, 0, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
1724 target_attrname, jcr->last_fname, be.bstrerror());
1725 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
1726 target_attrname, jcr->last_fname, be.bstrerror());
1732 * Successfully restored xattr.
1734 retval = bsub_exit_ok;
1738 Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
1740 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
1747 if (attrdirfd != -1) {
1756 static bsub_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt, int default_stream)
1759 bsub_exit_code retval = bsub_exit_ok;
1762 * First see if extended attributes or extensible attributes are present.
1763 * If not just pretend things went ok.
1765 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1769 * As we change the cwd in the save function save the current cwd
1770 * for restore after return from the solaris_save_xattrs function.
1772 xattr_link_cache = New(alist(10, not_owned_by_alist));
1773 getcwd(cwd, sizeof(cwd));
1774 retval = solaris_save_xattrs(jcr, NULL, NULL);
1776 delete xattr_link_cache;
1777 xattr_link_cache = NULL;
1782 static bsub_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
1785 bool is_extensible = false;
1786 bsub_exit_code retval;
1789 * First make sure we can restore xattr on the filesystem.
1792 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1793 case STREAM_XATTR_SOLARIS_SYS:
1794 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1795 Qmsg1(jcr, M_WARNING, 0,
1796 _("Failed to restore extensible attributes on file \"%s\"\n"),
1798 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1800 return bsub_exit_nok;
1803 is_extensible = true;
1806 case STREAM_XATTR_SOLARIS:
1807 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1808 Qmsg1(jcr, M_WARNING, 0,
1809 _("Failed to restore extended attributes on file \"%s\"\n"),
1811 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1813 return bsub_exit_nok;
1817 return bsub_exit_nok;
1821 * As we change the cwd in the restore function save the current cwd
1822 * for restore after return from the solaris_restore_xattrs function.
1824 getcwd(cwd, sizeof(cwd));
1825 retval = solaris_restore_xattrs(jcr, is_extensible);
1832 * Function pointers to the build and parse function to use for these xattrs.
1834 static bsub_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt, int default_stream) = solaris_build_xattr_streams;
1835 static bsub_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
1837 #endif /* defined(HAVE_SUN_OS) */
1839 bsub_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1841 if (os_build_xattr_streams) {
1842 return (*os_build_xattr_streams)(jcr, ff_pkt, os_default_xattr_streams[0]);
1844 return bsub_exit_nok;
1847 bsub_exit_code parse_xattr_streams(JCR *jcr, int stream)
1851 if (os_parse_xattr_streams) {
1853 * See if we can parse this stream, and ifso give it a try.
1855 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
1856 if (os_default_xattr_streams[cnt] == stream) {
1857 return (*os_parse_xattr_streams)(jcr, stream);
1862 * Issue a warning and discard the message. But pretend the restore was ok.
1864 Jmsg2(jcr, M_WARNING, 0,
1865 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1866 jcr->last_fname, stream);
1867 return bsub_exit_nok;