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 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
135 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
136 #elif defined(HAVE_FREEBSD_OS)
137 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
138 static const char *xattr_acl_skiplist[1] = { NULL };
139 static const char *xattr_skiplist[1] = { NULL };
140 #elif defined(HAVE_LINUX_OS)
141 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
142 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
143 static const char *xattr_skiplist[1] = { NULL };
144 #elif defined(HAVE_NETBSD_OS)
145 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
146 static const char *xattr_acl_skiplist[1] = { NULL };
147 static const char *xattr_skiplist[1] = { NULL };
151 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
152 * listxattr, getxattr and setxattr with an extra options argument
153 * which mimics the l variants of the functions when we specify
154 * XATTR_NOFOLLOW as the options value.
156 #if defined(HAVE_DARWIN_OS)
157 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
158 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
159 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
162 * Fallback to the non l-functions when those are not available.
164 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
165 #define lgetxattr getxattr
167 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
168 #define lsetxattr setxattr
170 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
171 #define llistxattr listxattr
175 static void xattr_drop_internal_table(xattr_t *xattr_value_list)
177 xattr_t *current_xattr;
180 * Walk the list of xattrs and free allocated memory on traversing.
182 for (current_xattr = xattr_value_list;
183 current_xattr != (xattr_t *)NULL;
186 * See if we can shortcut.
188 if (current_xattr->magic != XATTR_MAGIC)
191 free(current_xattr->name);
193 if (current_xattr->value_length > 0)
194 free(current_xattr->value);
198 * Free the array of control structs.
200 free(xattr_value_list);
204 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
205 * which encodes one or more xattr_t structures.
207 * The Serialized stream consists of the following elements:
208 * magic - A magic string which makes it easy to detect any binary incompatabilites
209 * name_length - The length of the following xattr name
210 * name - The name of the extended attribute
211 * value_length - The length of the following xattr data
212 * value - The actual content of the extended attribute
214 * This is repeated 1 or more times.
217 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list)
219 xattr_t *current_xattr;
223 * Make sure the serialized stream fits in the poolmem buffer.
224 * We allocate some more to be sure the stream is gonna fit.
226 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
227 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
230 * Walk the list of xattrs and serialize the data.
232 for (current_xattr = xattr_value_list; current_xattr != (xattr_t *)NULL; current_xattr++) {
234 * See if we can shortcut.
236 if (current_xattr->magic != XATTR_MAGIC)
239 ser_uint32(current_xattr->magic);
240 ser_uint32(current_xattr->name_length);
241 ser_bytes(current_xattr->name, current_xattr->name_length);
243 ser_uint32(current_xattr->value_length);
244 ser_bytes(current_xattr->value, current_xattr->value_length);
247 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
248 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
249 return jcr->xattr_data->content_length;
252 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
255 int cnt, xattr_count = 0;
256 int32_t xattr_list_len,
258 uint32_t expected_serialize_len = 0;
259 char *xattr_list, *bp;
260 xattr_t *xattr_value_list = NULL, *current_xattr;
261 bxattr_exit_code retval = bxattr_exit_error;
265 * First get the length of the available list with extended attributes.
267 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
268 if (xattr_list_len < 0) {
271 return bxattr_exit_ok;
273 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
274 jcr->last_fname, be.bstrerror());
275 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
276 jcr->last_fname, be.bstrerror());
277 return bxattr_exit_error;
279 } else if (xattr_list_len == 0) {
280 return bxattr_exit_ok;
284 * Allocate room for the extented attribute list.
286 xattr_list = (char *)malloc(xattr_list_len + 1);
287 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
290 * Get the actual list of extended attributes names for a file.
292 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
293 if (xattr_list_len < 0) {
296 retval = bxattr_exit_ok;
299 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
300 jcr->last_fname, be.bstrerror());
301 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
302 jcr->last_fname, be.bstrerror());
306 xattr_list[xattr_list_len] = '\0';
309 * Count the number of extended attributes on a file.
312 while ((bp - xattr_list) + 1 < xattr_list_len) {
316 * On some OSes you also get the acls in the extented attribute list.
317 * So we check if we are already backing up acls and if we do we
318 * don't store the extended attribute with the same info.
320 if (ff_pkt->flags & FO_ACL) {
321 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
322 if (!strcmp(bp, xattr_acl_skiplist[cnt])) {
330 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
333 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
334 if (!strcmp(bp, xattr_skiplist[cnt])) {
344 bp = strchr(bp, '\0') + 1;
347 if (xattr_count == 0) {
348 retval = bxattr_exit_ok;
353 * Allocate enough room to hold all extended attributes.
354 * After allocating the storage make sure its empty by zeroing it.
356 xattr_value_list = (xattr_t *)malloc(xattr_count * sizeof(xattr_t));
357 memset((caddr_t)xattr_value_list, 0, xattr_count * sizeof(xattr_t));
360 * Walk the list of extended attributes names and retrieve the data.
361 * We already count the bytes needed for serializing the stream later on.
363 current_xattr = xattr_value_list;
365 while ((bp - xattr_list) + 1 < xattr_list_len) {
369 * On some OSes you also get the acls in the extented attribute list.
370 * So we check if we are already backing up acls and if we do we
371 * don't store the extended attribute with the same info.
373 if (ff_pkt->flags & FO_ACL) {
374 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
375 if (!strcmp(bp, xattr_acl_skiplist[cnt])) {
383 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
386 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
387 if (!strcmp(bp, xattr_skiplist[cnt])) {
395 bp = strchr(bp, '\0') + 1;
400 * Each xattr valuepair starts with a magic so we can parse it easier.
402 current_xattr->magic = XATTR_MAGIC;
403 expected_serialize_len += sizeof(current_xattr->magic);
406 * Allocate space for storing the name.
408 current_xattr->name_length = strlen(bp);
409 current_xattr->name = (char *)malloc(current_xattr->name_length);
410 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
412 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
415 * First see how long the value is for the extended attribute.
417 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
418 if (xattr_value_len < 0) {
421 retval = bxattr_exit_ok;
424 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
425 jcr->last_fname, be.bstrerror());
426 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
427 jcr->last_fname, be.bstrerror());
433 * Allocate space for storing the value.
435 current_xattr->value = (char *)malloc(xattr_value_len);
436 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
438 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
439 if (xattr_value_len < 0) {
442 retval = bxattr_exit_ok;
445 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
446 jcr->last_fname, be.bstrerror());
447 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
448 jcr->last_fname, be.bstrerror());
454 * Store the actual length of the value.
456 current_xattr->value_length = xattr_value_len;
457 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
460 * Protect ourself against things getting out of hand.
462 if (expected_serialize_len >= MAX_XATTR_STREAM) {
463 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
464 jcr->last_fname, MAX_XATTR_STREAM);
472 bp = strchr(bp, '\0') + 1;
476 * Serialize the datastream.
478 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
479 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
481 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
486 xattr_drop_internal_table(xattr_value_list);
490 * Send the datastream to the SD.
492 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
495 if (xattr_value_list) {
496 xattr_drop_internal_table(xattr_value_list);
502 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
505 xattr_t current_xattr;
506 bxattr_exit_code retval = bxattr_exit_ok;
510 * Parse the stream and perform the setxattr calls on the file.
512 * Start unserializing the data. We keep on looping while we have not
513 * unserialized all bytes in the stream.
515 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
516 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
518 * First make sure the magic is present. This way we can easily catch corruption.
519 * Any missing MAGIC is fatal we do NOT try to continue.
521 unser_uint32(current_xattr.magic);
522 if (current_xattr.magic != XATTR_MAGIC) {
523 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
525 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
527 return bxattr_exit_error;
531 * Decode the valuepair. First decode the length of the name.
533 unser_uint32(current_xattr.name_length);
536 * Allocate room for the name and decode its content.
538 current_xattr.name = (char *)malloc(current_xattr.name_length + 1);
539 unser_bytes(current_xattr.name, current_xattr.name_length);
542 * The xattr_name needs to be null terminated for lsetxattr.
544 current_xattr.name[current_xattr.name_length] = '\0';
547 * Decode the value length.
549 unser_uint32(current_xattr.value_length);
552 * Allocate room for the value and decode its content.
554 current_xattr.value = (char *)malloc(current_xattr.value_length);
555 unser_bytes(current_xattr.value, current_xattr.value_length);
558 * Try to set the extended attribute on the file.
559 * If we fail to set this attribute we flag the error but its not fatal,
560 * we try to restore the other extended attributes too.
562 if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
563 current_xattr.value_length, 0) != 0) {
568 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
569 jcr->last_fname, be.bstrerror());
570 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
571 jcr->last_fname, be.bstrerror());
572 retval = bxattr_exit_error;
578 * Free the temporary buffers.
580 free(current_xattr.name);
581 free(current_xattr.value);
584 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
589 * For all these os-es setup the build and parse function pointer to the generic functions.
591 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
592 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
594 #elif defined(HAVE_SUN_OS)
596 * Solaris extended attributes were introduced in Solaris 9
599 * Solaris extensible attributes were introduced in OpenSolaris
600 * by PSARC 2007/315 Solaris extensible attributes are also
601 * sometimes called extended system attributes.
603 * man fsattr(5) on Solaris gives a wealth of info. The most
604 * important bits are:
606 * Attributes are logically supported as files within the file
607 * system. The file system is therefore augmented with an
608 * orthogonal name space of file attributes. Any file (includ-
609 * ing attribute files) can have an arbitrarily deep attribute
610 * tree associated with it. Attribute values are accessed by
611 * file descriptors obtained through a special attribute inter-
612 * face. This logical view of "attributes as files" allows the
613 * leveraging of existing file system interface functionality
614 * to support the construction, deletion, and manipulation of
617 * The special files "." and ".." retain their accustomed
618 * semantics within the attribute hierarchy. The "." attribute
619 * file refers to the current directory and the ".." attribute
620 * file refers to the parent directory. The unnamed directory
621 * at the head of each attribute tree is considered the "child"
622 * of the file it is associated with and the ".." file refers
623 * to the associated file. For any non-directory file with
624 * attributes, the ".." entry in the unnamed directory refers
625 * to a file that is not a directory.
627 * Conceptually, the attribute model is fully general. Extended
628 * attributes can be any type of file (doors, links, direc-
629 * tories, and so forth) and can even have their own attributes
630 * (fully recursive). As a result, the attributes associated
631 * with a file could be an arbitrarily deep directory hierarchy
632 * where each attribute could have an equally complex attribute
633 * tree associated with it. Not all implementations are able
634 * to, or want to, support the full model. Implementation are
635 * therefore permitted to reject operations that are not sup-
636 * ported. For example, the implementation for the UFS file
637 * system allows only regular files as attributes (for example,
638 * no sub-directories) and rejects attempts to place attributes
641 * The following list details the operations that are rejected
642 * in the current implementation:
644 * link Any attempt to create links between
645 * attribute and non-attribute space
646 * is rejected to prevent security-
647 * related or otherwise sensitive
648 * attributes from being exposed, and
649 * therefore manipulable, as regular
652 * rename Any attempt to rename between
653 * attribute and non-attribute space
654 * is rejected to prevent an already
655 * linked file from being renamed and
656 * thereby circumventing the link res-
659 * mkdir, symlink, mknod Any attempt to create a "non-
660 * regular" file in attribute space is
661 * rejected to reduce the functional-
662 * ity, and therefore exposure and
663 * risk, of the initial implementa-
666 * The entire available name space has been allocated to "gen-
667 * eral use" to bring the implementation in line with the NFSv4
668 * draft standard [NFSv4]. That standard defines "named attri-
669 * butes" (equivalent to Solaris Extended Attributes) with no
670 * naming restrictions. All Sun applications making use of
671 * opaque extended attributes will use the prefix "SUNW".
674 #ifdef HAVE_SYS_ATTR_H
675 #include <sys/attr.h>
682 #ifdef HAVE_SYS_NVPAIR_H
683 #include <sys/nvpair.h>
686 #ifdef HAVE_SYS_ACL_H
691 * Define the supported XATTR streams for this OS
693 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
694 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
696 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
697 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
700 * This code creates a temporary cache with entries for each xattr which has
701 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
703 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
705 xattr_link_cache_entry_t *ptr;
707 foreach_alist(ptr, jcr->xattr_data->link_cache) {
708 if (ptr && ptr->inum == inum) {
715 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
717 xattr_link_cache_entry_t *ptr;
719 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
720 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
722 bstrncpy(ptr->target, target, sizeof(ptr->target));
723 jcr->xattr_data->link_cache->append(ptr);
726 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
728 * This function returns true if a non default extended system attribute
729 * list is associated with fd and returns false when an error has occured
730 * or when only extended system attributes other than archive,
731 * av_modified or crtime are set.
733 * The function returns true for the following cases:
735 * - any extended system attribute other than the default attributes
736 * ('archive', 'av_modified' and 'crtime') is set
737 * - nvlist has NULL name string
738 * - nvpair has data type of 'nvlist'
739 * - default data type.
741 static bool solaris_has_non_transient_extensible_attributes(int fd)
751 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
756 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
757 name = nvpair_name(pair);
760 fattr = name_to_attr(name);
766 type = nvpair_type(pair);
768 case DATA_TYPE_BOOLEAN_VALUE:
769 if (nvpair_value_boolean_value(pair, &value) != 0) {
772 if (value && fattr != F_ARCHIVE &&
773 fattr != F_AV_MODIFIED) {
778 case DATA_TYPE_UINT64_ARRAY:
779 if (fattr != F_CRTIME) {
784 case DATA_TYPE_NVLIST:
792 if (response != NULL) {
793 nvlist_free(response);
797 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
799 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
801 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
802 * There is no need to store those acls as we already store the stat bits too.
804 static bool acl_is_trivial(int count, aclent_t *entries)
809 for (n = 0; n < count; n++) {
811 if (!(ace->a_type == USER_OBJ ||
812 ace->a_type == GROUP_OBJ ||
813 ace->a_type == OTHER_OBJ ||
814 ace->a_type == CLASS_OBJ))
819 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
821 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
824 #ifdef HAVE_EXTENDED_ACL
830 * See if this attribute has an ACL
832 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
833 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
835 * See if there is a non trivial acl on the file.
837 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
838 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
841 return bxattr_exit_ok;
843 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
844 attrname, jcr->last_fname, be.bstrerror());
845 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
846 attrname, jcr->last_fname, be.bstrerror());
847 return bxattr_exit_error;
852 #if defined(ACL_SID_FMT)
854 * New format flag added in newer Solaris versions.
856 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
858 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
859 #endif /* ACL_SID_FMT */
861 *acl_text = acl_totext(aclp, flags);
869 return bxattr_exit_ok;
870 #else /* HAVE_EXTENDED_ACL */
872 aclent_t *acls = NULL;
876 * See if this attribute has an ACL
879 n = facl(fd, GETACLCNT, 0, NULL);
881 n = acl(attrname, GETACLCNT, 0, NULL);
884 if (n >= MIN_ACL_ENTRIES) {
885 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
886 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
887 acl(attrname, GETACL, n, acls) != n) {
891 return bxattr_exit_ok;
893 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
894 attrname, jcr->last_fname, be.bstrerror());
895 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
896 attrname, jcr->last_fname, be.bstrerror());
898 return bxattr_exit_error;
903 * See if there is a non trivial acl on the file.
905 if (!acl_is_trivial(n, acls)) {
906 if ((*acl_text = acltotext(acls, n)) == NULL) {
907 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
908 attrname, jcr->last_fname, be.bstrerror());
909 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
910 attrname, jcr->last_fname, be.bstrerror());
912 return bxattr_exit_error;
922 return bxattr_exit_ok;
923 #endif /* HAVE_EXTENDED_ACL */
926 return bxattr_exit_ok;
927 #endif /* HAVE_ACL */
931 * Forward declaration for recursive function call.
933 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
936 * Save an extended or extensible attribute.
937 * This is stored as an opaque stream of bytes with the following encoding:
939 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
941 * or for a hardlinked or symlinked attribute
943 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
945 * xattr_name can be a subpath relative to the file the xattr is on.
946 * stat_buffer is the string representation of the stat struct.
947 * acl_string is an acl text when a non trivial acl is set on the xattr.
948 * actual_xattr_data is the content of the xattr file.
950 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
951 const char *attrname, bool toplevel_hidden_dir, int stream)
956 xattr_link_cache_entry_t *xlce;
957 char target_attrname[PATH_MAX];
958 char link_source[PATH_MAX];
959 char *acl_text = NULL;
960 char attribs[MAXSTRING];
962 bxattr_exit_code retval = bxattr_exit_error;
965 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
968 * Get the stats of the extended or extensible attribute.
970 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
973 retval = bxattr_exit_ok;
976 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
977 target_attrname, jcr->last_fname, be.bstrerror());
978 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
979 target_attrname, jcr->last_fname, be.bstrerror());
985 * Based on the filetype perform the correct action. We support most filetypes here, more
986 * then the actual implementation on Solaris supports so some code may never get executed
987 * due to limitations in the implementation.
989 switch (st.st_mode & S_IFMT) {
994 * Get any acl on the xattr.
996 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1000 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1001 * Encode the stat struct into an ASCII representation.
1003 encode_stat(attribs, &st, 0, stream);
1004 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
1005 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1009 * Get any acl on the xattr.
1011 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1015 * See if this is the toplevel_hidden_dir being saved.
1017 if (toplevel_hidden_dir) {
1019 * Save the data for later storage when we encounter a real xattr. We store the data
1020 * in the jcr->xattr_data->content buffer and flush that just before sending out the
1021 * first real xattr. Encode the stat struct into an ASCII representation and jump
1022 * out of the function.
1024 encode_stat(attribs, &st, 0, stream);
1025 cnt = bsnprintf(buffer, sizeof(buffer),
1027 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1028 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1029 jcr->xattr_data->content_length = cnt;
1033 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1034 * Encode the stat struct into an ASCII representation.
1036 encode_stat(attribs, &st, 0, stream);
1037 cnt = bsnprintf(buffer, sizeof(buffer),
1039 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1044 * If this is a hardlinked file check the inode cache for a hit.
1046 if (st.st_nlink > 1) {
1048 * See if the cache already knows this inode number.
1050 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
1052 * Generate a xattr encoding with the reference to the target in there.
1054 encode_stat(attribs, &st, st.st_ino, stream);
1055 cnt = bsnprintf(buffer, sizeof(buffer),
1057 target_attrname, 0, attribs, 0, xlce->target, 0);
1058 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1059 jcr->xattr_data->content_length = cnt;
1060 retval = send_xattr_stream(jcr, stream);
1063 * For a hard linked file we are ready now, no need to recursively save the attributes.
1069 * Store this hard linked file in the cache.
1070 * Store the name relative to the top level xattr space.
1072 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
1076 * Get any acl on the xattr.
1078 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
1083 * Encode the stat struct into an ASCII representation.
1085 encode_stat(attribs, &st, 0, stream);
1086 cnt = bsnprintf(buffer, sizeof(buffer),
1088 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1091 * Open the extended or extensible attribute file.
1093 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1096 retval = bxattr_exit_ok;
1099 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1100 target_attrname, jcr->last_fname, be.bstrerror());
1101 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1102 target_attrname, jcr->last_fname, be.bstrerror());
1109 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1110 * Encode the stat struct into an ASCII representation.
1112 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1115 retval = bxattr_exit_ok;
1118 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1119 target_attrname, jcr->last_fname, be.bstrerror());
1120 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1121 target_attrname, jcr->last_fname, be.bstrerror());
1127 * Generate a xattr encoding with the reference to the target in there.
1129 encode_stat(attribs, &st, st.st_ino, stream);
1130 cnt = bsnprintf(buffer, sizeof(buffer),
1132 target_attrname, 0, attribs, 0, link_source, 0);
1133 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1134 jcr->xattr_data->content_length = cnt;
1135 retval = send_xattr_stream(jcr, stream);
1137 if (retval == bxattr_exit_ok) {
1138 jcr->xattr_data->nr_saved++;
1142 * For a soft linked file we are ready now, no need to recursively save the attributes.
1150 * See if this is the first real xattr being saved.
1151 * If it is save the toplevel_hidden_dir attributes first.
1152 * This is easy as its stored already in the jcr->xattr_data->content buffer.
1154 if (jcr->xattr_data->nr_saved == 0) {
1155 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1156 if (retval != bxattr_exit_ok) {
1159 jcr->xattr_data->nr_saved++;
1162 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1163 jcr->xattr_data->content_length = cnt;
1166 * Only dump the content of regular files.
1168 switch (st.st_mode & S_IFMT) {
1170 if (st.st_size > 0) {
1172 * Protect ourself against things getting out of hand.
1174 if (st.st_size >= MAX_XATTR_STREAM) {
1175 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1176 jcr->last_fname, MAX_XATTR_STREAM);
1180 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1181 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
1182 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
1183 jcr->xattr_data->content_length += cnt;
1187 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
1188 target_attrname, jcr->last_fname);
1189 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1190 target_attrname, jcr->last_fname);
1201 retval = send_xattr_stream(jcr, stream);
1202 if (retval == bxattr_exit_ok) {
1203 jcr->xattr_data->nr_saved++;
1208 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1209 * available on this extended attribute.
1212 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1215 * The recursive call could change our working dir so change back to the wanted workdir.
1217 if (fchdir(fd) < 0) {
1220 retval = bxattr_exit_ok;
1223 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1224 jcr->last_fname, be.bstrerror());
1225 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1226 jcr->last_fname, fd, be.bstrerror());
1242 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1245 int fd, filefd = -1, attrdirfd = -1;
1248 char current_xattr_namespace[PATH_MAX];
1249 bxattr_exit_code retval = bxattr_exit_error;
1253 * Determine what argument to use. Use attr_parent when set
1254 * (recursive call) or jcr->last_fname for first call. Also save
1255 * the current depth of the xattr_space we are in.
1259 if (xattr_namespace) {
1260 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1261 xattr_namespace, attr_parent);
1263 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1266 name = jcr->last_fname;
1267 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1271 * Open the file on which to save the xattrs read-only.
1273 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1276 retval = bxattr_exit_ok;
1279 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1280 jcr->last_fname, be.bstrerror());
1281 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1282 jcr->last_fname, be.bstrerror());
1288 * Open the xattr naming space.
1290 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1294 * Gentile way of the system saying this type of xattr layering is not supported.
1295 * Which is not problem we just forget about this this xattr.
1296 * But as this is not an error we return a positive return value.
1298 retval = bxattr_exit_ok;
1301 retval = bxattr_exit_ok;
1304 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1305 name, jcr->last_fname, be.bstrerror());
1306 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1307 name, jcr->last_fname, be.bstrerror());
1313 * We need to change into the attribute directory to determine if each of the
1314 * attributes should be saved.
1316 if (fchdir(attrdirfd) < 0) {
1317 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1318 jcr->last_fname, be.bstrerror());
1319 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1320 jcr->last_fname, attrdirfd, be.bstrerror());
1325 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1326 * else because the readdir returns "." entry after the extensible attr entry.
1327 * And as we want this entry before anything else we better just save its data.
1330 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1331 true, STREAM_XATTR_SOLARIS);
1333 if ((fd = dup(attrdirfd)) == -1 ||
1334 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1335 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1336 jcr->last_fname, be.bstrerror());
1337 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1338 jcr->last_fname, fd, be.bstrerror());
1344 * Walk the namespace.
1346 while (dp = readdir(dirp)) {
1348 * Skip only the toplevel . dir.
1350 if (!attr_parent && !strcmp(dp->d_name, "."))
1354 * Skip all .. directories
1356 if (!strcmp(dp->d_name, ".."))
1359 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1360 current_xattr_namespace, dp->d_name, jcr->last_fname);
1362 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1364 * We are not interested in read-only extensible attributes.
1366 if (!strcmp(dp->d_name, VIEW_READONLY)) {
1367 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1368 current_xattr_namespace, dp->d_name, jcr->last_fname);
1374 * We are only interested in read-write extensible attributes
1375 * when they contain non-transient values.
1377 if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1379 * Determine if there are non-transient system attributes at the toplevel.
1380 * We need to provide a fd to the open file.
1382 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1383 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1384 current_xattr_namespace, dp->d_name, jcr->last_fname);
1391 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1392 false, STREAM_XATTR_SOLARIS_SYS);
1395 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1400 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1401 false, STREAM_XATTR_SOLARIS);
1405 retval = bxattr_exit_ok;
1408 if (attrdirfd != -1)
1416 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1418 #ifdef HAVE_EXTENDED_ACL
1423 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1424 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
1426 return bxattr_exit_error;
1429 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1430 acl_set(attrname, aclp) != 0) {
1431 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1432 attrname, jcr->last_fname, be.bstrerror());
1433 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1434 attrname, jcr->last_fname, be.bstrerror());
1435 return bxattr_exit_error;
1441 return bxattr_exit_ok;
1443 #else /* HAVE_EXTENDED_ACL */
1445 aclent_t *acls = NULL;
1448 acls = aclfromtext(acl_text, &n);
1450 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1451 acl(attrname, SETACL, n, acls) != 0) {
1452 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1453 attrname, jcr->last_fname, be.bstrerror());
1454 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1455 attrname, jcr->last_fname, be.bstrerror());
1456 return bxattr_exit_error;
1463 return bxattr_exit_ok;
1465 #endif /* HAVE_EXTENDED_ACL */
1468 #endif /* HAVE_ACL */
1470 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1472 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1473 int used_bytes, total_bytes, cnt;
1474 char *bp, *target_attrname, *attribs;
1475 char *linked_target = NULL;
1476 char *acl_text = NULL;
1480 struct timeval times[2];
1481 bxattr_exit_code retval = bxattr_exit_error;
1485 * Parse the xattr stream. First the part that is the same for all xattrs.
1488 total_bytes = jcr->xattr_data->content_length;
1491 * The name of the target xattr has a leading / we are not interested
1492 * in that so skip it when decoding the string. We always start a the /
1493 * of the xattr space anyway.
1495 target_attrname = jcr->xattr_data->content + 1;
1496 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1497 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1503 * Open the file on which to restore the xattrs read-only.
1505 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1506 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1507 jcr->last_fname, be.bstrerror());
1508 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1509 jcr->last_fname, be.bstrerror());
1514 * Open the xattr naming space and make it the current working dir.
1516 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1517 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1518 jcr->last_fname, be.bstrerror());
1519 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1520 jcr->last_fname, be.bstrerror());
1524 if (fchdir(attrdirfd) < 0) {
1525 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1526 jcr->last_fname, be.bstrerror());
1527 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1528 jcr->last_fname, attrdirfd, be.bstrerror());
1533 * Try to open the correct xattr subdir based on the target_attrname given.
1534 * e.g. check if its a subdir attrname. Each / in the string makes us go
1537 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1540 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1541 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1542 target_attrname, jcr->last_fname, be.bstrerror());
1543 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1544 target_attrname, jcr->last_fname, be.bstrerror());
1552 * Open the xattr naming space.
1554 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1555 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1556 target_attrname, jcr->last_fname, be.bstrerror());
1557 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1558 target_attrname, jcr->last_fname, be.bstrerror());
1566 * Make the xattr space our current workingdir.
1568 if (fchdir(attrdirfd) < 0) {
1569 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1570 target_attrname, jcr->last_fname, be.bstrerror());
1571 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1572 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1576 target_attrname = ++bp;
1580 * Decode the attributes from the stream.
1582 decode_stat(attribs, &st, &inum);
1585 * Decode the next field (acl_text).
1587 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1588 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1594 * Based on the filetype perform the correct action. We support most filetypes here, more
1595 * then the actual implementation on Solaris supports so some code may never get executed
1596 * due to limitations in the implementation.
1598 switch (st.st_mode & S_IFMT) {
1601 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1603 unlinkat(attrdirfd, target_attrname, 0);
1604 if (mkfifo(target_attrname, st.st_mode) < 0) {
1605 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1606 target_attrname, jcr->last_fname, be.bstrerror());
1607 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1608 target_attrname, jcr->last_fname, be.bstrerror());
1615 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1617 unlinkat(attrdirfd, target_attrname, 0);
1618 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1619 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1620 target_attrname, jcr->last_fname, be.bstrerror());
1621 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1622 target_attrname, jcr->last_fname, be.bstrerror());
1628 * If its not the hidden_dir create the entry.
1629 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1631 if (strcmp(target_attrname, ".")) {
1632 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1633 if (mkdir(target_attrname, st.st_mode) < 0) {
1634 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1635 target_attrname, jcr->last_fname, be.bstrerror());
1636 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1637 target_attrname, jcr->last_fname, be.bstrerror());
1644 * See if this is a hard linked file. e.g. inum != 0
1649 unlinkat(attrdirfd, target_attrname, 0);
1650 if (link(linked_target, target_attrname) < 0) {
1651 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1652 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1653 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1654 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1659 * Successfully restored xattr.
1661 retval = bxattr_exit_ok;
1664 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1665 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
1669 if (used_bytes < (total_bytes - 1))
1673 * Restore the actual xattr.
1675 if (!is_extensible) {
1676 unlinkat(attrdirfd, target_attrname, 0);
1679 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1680 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1681 target_attrname, jcr->last_fname, be.bstrerror());
1682 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1683 target_attrname, jcr->last_fname, be.bstrerror());
1689 * Restore the actual data.
1691 if (st.st_size > 0) {
1692 used_bytes = (data - jcr->xattr_data->content);
1693 cnt = total_bytes - used_bytes;
1696 * Do a sanity check, the st.st_size should be the same as the number of bytes
1697 * we have available as data of the stream.
1699 if (cnt != st.st_size) {
1700 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
1701 target_attrname, jcr->last_fname);
1702 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1703 target_attrname, jcr->last_fname);
1708 cnt = write(attrfd, data, cnt);
1710 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
1711 target_attrname, jcr->last_fname, be.bstrerror());
1712 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
1713 target_attrname, jcr->last_fname, be.bstrerror());
1719 cnt = total_bytes - used_bytes;
1725 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1729 if (symlink(linked_target, target_attrname) < 0) {
1730 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
1731 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1732 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
1733 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1738 * Successfully restored xattr.
1740 retval = bxattr_exit_ok;
1747 * Restore owner and acl for non extensible attributes.
1749 if (!is_extensible) {
1750 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
1754 * Gentile way of the system saying this type of xattr layering is not supported.
1755 * But as this is not an error we return a positive return value.
1757 retval = bxattr_exit_ok;
1760 retval = bxattr_exit_ok;
1763 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1764 target_attrname, jcr->last_fname, be.bstrerror());
1765 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1766 target_attrname, jcr->last_fname, be.bstrerror());
1773 if (acl_text && *acl_text)
1774 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
1776 #endif /* HAVE_ACL */
1779 * For a non extensible attribute restore access and modification time on the xattr.
1781 if (!is_extensible) {
1782 times[0].tv_sec = st.st_atime;
1783 times[0].tv_usec = 0;
1784 times[1].tv_sec = st.st_mtime;
1785 times[1].tv_usec = 0;
1787 if (futimesat(attrdirfd, target_attrname, times) < 0) {
1788 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
1789 target_attrname, jcr->last_fname, be.bstrerror());
1790 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
1791 target_attrname, jcr->last_fname, be.bstrerror());
1797 * Successfully restored xattr.
1799 retval = bxattr_exit_ok;
1803 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
1805 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
1812 if (attrdirfd != -1) {
1821 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1824 bxattr_exit_code retval = bxattr_exit_ok;
1827 * First see if extended attributes or extensible attributes are present.
1828 * If not just pretend things went ok.
1830 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1831 jcr->xattr_data->nr_saved = 0;
1832 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
1835 * As we change the cwd in the save function save the current cwd
1836 * for restore after return from the solaris_save_xattrs function.
1838 getcwd(cwd, sizeof(cwd));
1839 retval = solaris_save_xattrs(jcr, NULL, NULL);
1841 delete jcr->xattr_data->link_cache;
1842 jcr->xattr_data->link_cache = NULL;
1847 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
1850 bool is_extensible = false;
1851 bxattr_exit_code retval;
1854 * First make sure we can restore xattr on the filesystem.
1857 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1858 case STREAM_XATTR_SOLARIS_SYS:
1859 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1860 Qmsg1(jcr, M_WARNING, 0,
1861 _("Failed to restore extensible attributes on file \"%s\"\n"),
1863 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1865 return bxattr_exit_error;
1868 is_extensible = true;
1871 case STREAM_XATTR_SOLARIS:
1872 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1873 Qmsg1(jcr, M_WARNING, 0,
1874 _("Failed to restore extended attributes on file \"%s\"\n"),
1876 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1878 return bxattr_exit_error;
1882 return bxattr_exit_error;
1886 * As we change the cwd in the restore function save the current cwd
1887 * for restore after return from the solaris_restore_xattrs function.
1889 getcwd(cwd, sizeof(cwd));
1890 retval = solaris_restore_xattrs(jcr, is_extensible);
1897 * Function pointers to the build and parse function to use for these xattrs.
1899 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
1900 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
1902 #endif /* defined(HAVE_SUN_OS) */
1905 * Entry points when compiled with support for XATTRs on a supported platform.
1907 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1909 if (os_build_xattr_streams) {
1910 return (*os_build_xattr_streams)(jcr, ff_pkt);
1912 return bxattr_exit_error;
1915 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
1919 if (os_parse_xattr_streams) {
1921 * See if we can parse this stream, and ifso give it a try.
1923 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
1924 if (os_default_xattr_streams[cnt] == stream) {
1925 return (*os_parse_xattr_streams)(jcr, stream);
1930 * Issue a warning and discard the message. But pretend the restore was ok.
1932 Jmsg2(jcr, M_WARNING, 0,
1933 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1934 jcr->last_fname, stream);
1935 return bxattr_exit_error;