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 * - Darwin (Extended Attributes)
36 * - Linux (Extended Attributes)
37 * - NetBSD (Extended Attributes)
38 * - FreeBSD (Extended Attributes)
39 * - OpenBSD (Extended Attributes)
40 * - Solaris (Extended Attributes and Extensible Attributes)
42 * 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_LINUX_OS) || \
122 defined(HAVE_NETBSD_OS)
124 #ifdef HAVE_SYS_XATTR_H
125 #include <sys/xattr.h>
129 * Define the supported XATTR streams for this OS
131 #if defined(HAVE_DARWIN_OS)
132 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
133 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
134 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
135 #elif defined(HAVE_LINUX_OS)
136 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
137 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
138 static const char *xattr_skiplist[1] = { NULL };
142 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
143 * listxattr, getxattr and setxattr with an extra options argument
144 * which mimics the l variants of the functions when we specify
145 * XATTR_NOFOLLOW as the options value.
147 #if defined(HAVE_DARWIN_OS)
148 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
149 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
150 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
153 * Fallback to the non l-functions when those are not available.
155 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
156 #define lgetxattr getxattr
158 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
159 #define lsetxattr setxattr
161 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
162 #define llistxattr listxattr
166 static void xattr_drop_internal_table(xattr_t *xattr_value_list)
168 xattr_t *current_xattr;
171 * Walk the list of xattrs and free allocated memory on traversing.
173 for (current_xattr = xattr_value_list;
174 current_xattr != (xattr_t *)NULL;
177 * See if we can shortcut.
179 if (current_xattr->magic != XATTR_MAGIC)
182 free(current_xattr->name);
184 if (current_xattr->value_length > 0)
185 free(current_xattr->value);
189 * Free the array of control structs.
191 free(xattr_value_list);
195 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
196 * which encodes one or more xattr_t structures.
198 * The Serialized stream consists of the following elements:
199 * magic - A magic string which makes it easy to detect any binary incompatabilites
200 * name_length - The length of the following xattr name
201 * name - The name of the extended attribute
202 * value_length - The length of the following xattr data
203 * value - The actual content of the extended attribute
205 * This is repeated 1 or more times.
208 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list)
210 xattr_t *current_xattr;
214 * Make sure the serialized stream fits in the poolmem buffer.
215 * We allocate some more to be sure the stream is gonna fit.
217 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
218 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
221 * Walk the list of xattrs and serialize the data.
223 for (current_xattr = xattr_value_list; current_xattr != (xattr_t *)NULL; current_xattr++) {
225 * See if we can shortcut.
227 if (current_xattr->magic != XATTR_MAGIC)
230 ser_uint32(current_xattr->magic);
231 ser_uint32(current_xattr->name_length);
232 ser_bytes(current_xattr->name, current_xattr->name_length);
234 ser_uint32(current_xattr->value_length);
235 ser_bytes(current_xattr->value, current_xattr->value_length);
238 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
239 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
240 return jcr->xattr_data->content_length;
243 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
246 int cnt, xattr_count = 0;
247 int32_t xattr_list_len,
249 uint32_t expected_serialize_len = 0;
250 char *xattr_list, *bp;
251 xattr_t *xattr_value_list = NULL, *current_xattr;
252 bxattr_exit_code retval = bxattr_exit_error;
256 * First get the length of the available list with extended attributes.
258 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
259 if (xattr_list_len < 0) {
262 return bxattr_exit_ok;
264 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
265 jcr->last_fname, be.bstrerror());
266 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
267 jcr->last_fname, be.bstrerror());
268 return bxattr_exit_error;
270 } else if (xattr_list_len == 0) {
271 return bxattr_exit_ok;
275 * Allocate room for the extented attribute list.
277 xattr_list = (char *)malloc(xattr_list_len + 1);
278 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
281 * Get the actual list of extended attributes names for a file.
283 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
284 if (xattr_list_len < 0) {
287 retval = bxattr_exit_ok;
290 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
291 jcr->last_fname, be.bstrerror());
292 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
293 jcr->last_fname, be.bstrerror());
297 xattr_list[xattr_list_len] = '\0';
300 * Count the number of extended attributes on a file.
303 while ((bp - xattr_list) + 1 < xattr_list_len) {
307 * On some OSes you also get the acls in the extented attribute list.
308 * So we check if we are already backing up acls and if we do we
309 * don't store the extended attribute with the same info.
311 if (ff_pkt->flags & FO_ACL) {
312 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
313 if (!strcmp(bp, xattr_acl_skiplist[cnt])) {
321 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
324 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
325 if (!strcmp(bp, xattr_skiplist[cnt])) {
335 bp = strchr(bp, '\0') + 1;
338 if (xattr_count == 0) {
339 retval = bxattr_exit_ok;
344 * Allocate enough room to hold all extended attributes.
345 * After allocating the storage make sure its empty by zeroing it.
347 xattr_value_list = (xattr_t *)malloc(xattr_count * sizeof(xattr_t));
348 memset((caddr_t)xattr_value_list, 0, xattr_count * sizeof(xattr_t));
351 * Walk the list of extended attributes names and retrieve the data.
352 * We already count the bytes needed for serializing the stream later on.
354 current_xattr = xattr_value_list;
356 while ((bp - xattr_list) + 1 < xattr_list_len) {
360 * On some OSes you also get the acls in the extented attribute list.
361 * So we check if we are already backing up acls and if we do we
362 * don't store the extended attribute with the same info.
364 if (ff_pkt->flags & FO_ACL) {
365 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
366 if (!strcmp(bp, xattr_acl_skiplist[cnt])) {
374 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
377 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
378 if (!strcmp(bp, xattr_skiplist[cnt])) {
386 bp = strchr(bp, '\0') + 1;
391 * Each xattr valuepair starts with a magic so we can parse it easier.
393 current_xattr->magic = XATTR_MAGIC;
394 expected_serialize_len += sizeof(current_xattr->magic);
397 * Allocate space for storing the name.
399 current_xattr->name_length = strlen(bp);
400 current_xattr->name = (char *)malloc(current_xattr->name_length);
401 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
403 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
406 * First see how long the value is for the extended attribute.
408 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
409 if (xattr_value_len < 0) {
412 retval = bxattr_exit_ok;
415 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
416 jcr->last_fname, be.bstrerror());
417 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
418 jcr->last_fname, be.bstrerror());
424 * Allocate space for storing the value.
426 current_xattr->value = (char *)malloc(xattr_value_len);
427 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
429 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
430 if (xattr_value_len < 0) {
433 retval = bxattr_exit_ok;
436 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
437 jcr->last_fname, be.bstrerror());
438 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
439 jcr->last_fname, be.bstrerror());
445 * Store the actual length of the value.
447 current_xattr->value_length = xattr_value_len;
448 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
451 * Protect ourself against things getting out of hand.
453 if (expected_serialize_len >= MAX_XATTR_STREAM) {
454 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
455 jcr->last_fname, MAX_XATTR_STREAM);
463 bp = strchr(bp, '\0') + 1;
467 * Serialize the datastream.
469 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
470 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
472 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
477 xattr_drop_internal_table(xattr_value_list);
481 * Send the datastream to the SD.
483 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
486 if (xattr_value_list) {
487 xattr_drop_internal_table(xattr_value_list);
493 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
496 xattr_t current_xattr;
497 bxattr_exit_code retval = bxattr_exit_ok;
501 * Parse the stream and perform the setxattr calls on the file.
503 * Start unserializing the data. We keep on looping while we have not
504 * unserialized all bytes in the stream.
506 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
507 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
509 * First make sure the magic is present. This way we can easily catch corruption.
510 * Any missing MAGIC is fatal we do NOT try to continue.
512 unser_uint32(current_xattr.magic);
513 if (current_xattr.magic != XATTR_MAGIC) {
514 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
516 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
518 return bxattr_exit_error;
522 * Decode the valuepair. First decode the length of the name.
524 unser_uint32(current_xattr.name_length);
527 * Allocate room for the name and decode its content.
529 current_xattr.name = (char *)malloc(current_xattr.name_length + 1);
530 unser_bytes(current_xattr.name, current_xattr.name_length);
533 * The xattr_name needs to be null terminated for lsetxattr.
535 current_xattr.name[current_xattr.name_length] = '\0';
538 * Decode the value length.
540 unser_uint32(current_xattr.value_length);
543 * Allocate room for the value and decode its content.
545 current_xattr.value = (char *)malloc(current_xattr.value_length);
546 unser_bytes(current_xattr.value, current_xattr.value_length);
549 * Try to set the extended attribute on the file.
550 * If we fail to set this attribute we flag the error but its not fatal,
551 * we try to restore the other extended attributes too.
553 if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
554 current_xattr.value_length, 0) != 0) {
559 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
560 jcr->last_fname, be.bstrerror());
561 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
562 jcr->last_fname, be.bstrerror());
563 retval = bxattr_exit_error;
569 * Free the temporary buffers.
571 free(current_xattr.name);
572 free(current_xattr.value);
575 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
580 * For all these os-es setup the build and parse function pointer to the generic functions.
582 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
583 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
585 #elif defined(HAVE_FREEBSD_OS) || \
586 defined(HAVE_NETBSD_OS) || \
587 defined(HAVE_OPENBSD_OS)
589 #ifdef HAVE_SYS_EXTATTR_H
590 #include <sys/extattr.h>
593 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
594 static const char *xattr_acl_skiplist[1] = { NULL };
595 static const char *xattr_skiplist[1] = { NULL };
597 static bxattr_exit_code freebsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
599 bxattr_exit_code retval = bxattr_exit_ok;
604 static bxattr_exit_code freebsd_parse_xattr_streams(JCR *jcr, int stream)
606 bxattr_exit_code retval;
612 * Function pointers to the build and parse function to use for these xattrs.
614 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = freebsd_build_xattr_streams;
615 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = freebsd_parse_xattr_streams;
617 #elif defined(HAVE_SUN_OS)
619 * Solaris extended attributes were introduced in Solaris 9
622 * Solaris extensible attributes were introduced in OpenSolaris
623 * by PSARC 2007/315 Solaris extensible attributes are also
624 * sometimes called extended system attributes.
626 * man fsattr(5) on Solaris gives a wealth of info. The most
627 * important bits are:
629 * Attributes are logically supported as files within the file
630 * system. The file system is therefore augmented with an
631 * orthogonal name space of file attributes. Any file (includ-
632 * ing attribute files) can have an arbitrarily deep attribute
633 * tree associated with it. Attribute values are accessed by
634 * file descriptors obtained through a special attribute inter-
635 * face. This logical view of "attributes as files" allows the
636 * leveraging of existing file system interface functionality
637 * to support the construction, deletion, and manipulation of
640 * The special files "." and ".." retain their accustomed
641 * semantics within the attribute hierarchy. The "." attribute
642 * file refers to the current directory and the ".." attribute
643 * file refers to the parent directory. The unnamed directory
644 * at the head of each attribute tree is considered the "child"
645 * of the file it is associated with and the ".." file refers
646 * to the associated file. For any non-directory file with
647 * attributes, the ".." entry in the unnamed directory refers
648 * to a file that is not a directory.
650 * Conceptually, the attribute model is fully general. Extended
651 * attributes can be any type of file (doors, links, direc-
652 * tories, and so forth) and can even have their own attributes
653 * (fully recursive). As a result, the attributes associated
654 * with a file could be an arbitrarily deep directory hierarchy
655 * where each attribute could have an equally complex attribute
656 * tree associated with it. Not all implementations are able
657 * to, or want to, support the full model. Implementation are
658 * therefore permitted to reject operations that are not sup-
659 * ported. For example, the implementation for the UFS file
660 * system allows only regular files as attributes (for example,
661 * no sub-directories) and rejects attempts to place attributes
664 * The following list details the operations that are rejected
665 * in the current implementation:
667 * link Any attempt to create links between
668 * attribute and non-attribute space
669 * is rejected to prevent security-
670 * related or otherwise sensitive
671 * attributes from being exposed, and
672 * therefore manipulable, as regular
675 * rename Any attempt to rename between
676 * attribute and non-attribute space
677 * is rejected to prevent an already
678 * linked file from being renamed and
679 * thereby circumventing the link res-
682 * mkdir, symlink, mknod Any attempt to create a "non-
683 * regular" file in attribute space is
684 * rejected to reduce the functional-
685 * ity, and therefore exposure and
686 * risk, of the initial implementa-
689 * The entire available name space has been allocated to "gen-
690 * eral use" to bring the implementation in line with the NFSv4
691 * draft standard [NFSv4]. That standard defines "named attri-
692 * butes" (equivalent to Solaris Extended Attributes) with no
693 * naming restrictions. All Sun applications making use of
694 * opaque extended attributes will use the prefix "SUNW".
697 #ifdef HAVE_SYS_ATTR_H
698 #include <sys/attr.h>
705 #ifdef HAVE_SYS_NVPAIR_H
706 #include <sys/nvpair.h>
709 #ifdef HAVE_SYS_ACL_H
714 * Define the supported XATTR streams for this OS
716 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
717 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
719 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
720 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
723 * This code creates a temporary cache with entries for each xattr which has
724 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
726 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
728 xattr_link_cache_entry_t *ptr;
730 foreach_alist(ptr, jcr->xattr_data->link_cache) {
731 if (ptr && ptr->inum == inum) {
738 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
740 xattr_link_cache_entry_t *ptr;
742 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
743 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
745 bstrncpy(ptr->target, target, sizeof(ptr->target));
746 jcr->xattr_data->link_cache->append(ptr);
749 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
751 * This function returns true if a non default extended system attribute
752 * list is associated with fd and returns false when an error has occured
753 * or when only extended system attributes other than archive,
754 * av_modified or crtime are set.
756 * The function returns true for the following cases:
758 * - any extended system attribute other than the default attributes
759 * ('archive', 'av_modified' and 'crtime') is set
760 * - nvlist has NULL name string
761 * - nvpair has data type of 'nvlist'
762 * - default data type.
764 static bool solaris_has_non_transient_extensible_attributes(int fd)
774 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
779 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
780 name = nvpair_name(pair);
783 fattr = name_to_attr(name);
789 type = nvpair_type(pair);
791 case DATA_TYPE_BOOLEAN_VALUE:
792 if (nvpair_value_boolean_value(pair, &value) != 0) {
795 if (value && fattr != F_ARCHIVE &&
796 fattr != F_AV_MODIFIED) {
801 case DATA_TYPE_UINT64_ARRAY:
802 if (fattr != F_CRTIME) {
807 case DATA_TYPE_NVLIST:
815 if (response != NULL) {
816 nvlist_free(response);
820 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
822 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
824 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
825 * There is no need to store those acls as we already store the stat bits too.
827 static bool acl_is_trivial(int count, aclent_t *entries)
832 for (n = 0; n < count; n++) {
834 if (!(ace->a_type == USER_OBJ ||
835 ace->a_type == GROUP_OBJ ||
836 ace->a_type == OTHER_OBJ ||
837 ace->a_type == CLASS_OBJ))
842 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
844 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
847 #ifdef HAVE_EXTENDED_ACL
853 * See if this attribute has an ACL
855 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
856 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
858 * See if there is a non trivial acl on the file.
860 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
861 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
864 return bxattr_exit_ok;
866 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
867 attrname, jcr->last_fname, be.bstrerror());
868 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
869 attrname, jcr->last_fname, be.bstrerror());
870 return bxattr_exit_error;
875 #if defined(ACL_SID_FMT)
877 * New format flag added in newer Solaris versions.
879 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
881 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
882 #endif /* ACL_SID_FMT */
884 *acl_text = acl_totext(aclp, flags);
892 return bxattr_exit_ok;
893 #else /* HAVE_EXTENDED_ACL */
895 aclent_t *acls = NULL;
899 * See if this attribute has an ACL
902 n = facl(fd, GETACLCNT, 0, NULL);
904 n = acl(attrname, GETACLCNT, 0, NULL);
907 if (n >= MIN_ACL_ENTRIES) {
908 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
909 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
910 acl(attrname, GETACL, n, acls) != n) {
914 return bxattr_exit_ok;
916 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
917 attrname, jcr->last_fname, be.bstrerror());
918 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
919 attrname, jcr->last_fname, be.bstrerror());
921 return bxattr_exit_error;
926 * See if there is a non trivial acl on the file.
928 if (!acl_is_trivial(n, acls)) {
929 if ((*acl_text = acltotext(acls, n)) == NULL) {
930 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
931 attrname, jcr->last_fname, be.bstrerror());
932 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
933 attrname, jcr->last_fname, be.bstrerror());
935 return bxattr_exit_error;
945 return bxattr_exit_ok;
946 #endif /* HAVE_EXTENDED_ACL */
949 return bxattr_exit_ok;
950 #endif /* HAVE_ACL */
954 * Forward declaration for recursive function call.
956 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
959 * Save an extended or extensible attribute.
960 * This is stored as an opaque stream of bytes with the following encoding:
962 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
964 * or for a hardlinked or symlinked attribute
966 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
968 * xattr_name can be a subpath relative to the file the xattr is on.
969 * stat_buffer is the string representation of the stat struct.
970 * acl_string is an acl text when a non trivial acl is set on the xattr.
971 * actual_xattr_data is the content of the xattr file.
973 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
974 const char *attrname, bool toplevel_hidden_dir, int stream)
979 xattr_link_cache_entry_t *xlce;
980 char target_attrname[PATH_MAX];
981 char link_source[PATH_MAX];
982 char *acl_text = NULL;
983 char attribs[MAXSTRING];
985 bxattr_exit_code retval = bxattr_exit_error;
988 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
991 * Get the stats of the extended or extensible attribute.
993 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
996 retval = bxattr_exit_ok;
999 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
1000 target_attrname, jcr->last_fname, be.bstrerror());
1001 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
1002 target_attrname, jcr->last_fname, be.bstrerror());
1008 * Based on the filetype perform the correct action. We support most filetypes here, more
1009 * then the actual implementation on Solaris supports so some code may never get executed
1010 * due to limitations in the implementation.
1012 switch (st.st_mode & S_IFMT) {
1017 * Get any acl on the xattr.
1019 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1023 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1024 * Encode the stat struct into an ASCII representation.
1026 encode_stat(attribs, &st, 0, stream);
1027 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
1028 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1032 * Get any acl on the xattr.
1034 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1038 * See if this is the toplevel_hidden_dir being saved.
1040 if (toplevel_hidden_dir) {
1042 * Save the data for later storage when we encounter a real xattr. We store the data
1043 * in the jcr->xattr_data->content buffer and flush that just before sending out the
1044 * first real xattr. Encode the stat struct into an ASCII representation and jump
1045 * out of the function.
1047 encode_stat(attribs, &st, 0, stream);
1048 cnt = bsnprintf(buffer, sizeof(buffer),
1050 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1051 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1052 jcr->xattr_data->content_length = cnt;
1056 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1057 * Encode the stat struct into an ASCII representation.
1059 encode_stat(attribs, &st, 0, stream);
1060 cnt = bsnprintf(buffer, sizeof(buffer),
1062 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1067 * If this is a hardlinked file check the inode cache for a hit.
1069 if (st.st_nlink > 1) {
1071 * See if the cache already knows this inode number.
1073 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
1075 * Generate a xattr encoding with the reference to the target in there.
1077 encode_stat(attribs, &st, st.st_ino, stream);
1078 cnt = bsnprintf(buffer, sizeof(buffer),
1080 target_attrname, 0, attribs, 0, xlce->target, 0);
1081 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1082 jcr->xattr_data->content_length = cnt;
1083 retval = send_xattr_stream(jcr, stream);
1086 * For a hard linked file we are ready now, no need to recursively save the attributes.
1092 * Store this hard linked file in the cache.
1093 * Store the name relative to the top level xattr space.
1095 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
1099 * Get any acl on the xattr.
1101 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
1106 * Encode the stat struct into an ASCII representation.
1108 encode_stat(attribs, &st, 0, stream);
1109 cnt = bsnprintf(buffer, sizeof(buffer),
1111 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1114 * Open the extended or extensible attribute file.
1116 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1119 retval = bxattr_exit_ok;
1122 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1123 target_attrname, jcr->last_fname, be.bstrerror());
1124 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1125 target_attrname, jcr->last_fname, be.bstrerror());
1132 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1133 * Encode the stat struct into an ASCII representation.
1135 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1138 retval = bxattr_exit_ok;
1141 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1142 target_attrname, jcr->last_fname, be.bstrerror());
1143 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1144 target_attrname, jcr->last_fname, be.bstrerror());
1150 * Generate a xattr encoding with the reference to the target in there.
1152 encode_stat(attribs, &st, st.st_ino, stream);
1153 cnt = bsnprintf(buffer, sizeof(buffer),
1155 target_attrname, 0, attribs, 0, link_source, 0);
1156 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1157 jcr->xattr_data->content_length = cnt;
1158 retval = send_xattr_stream(jcr, stream);
1160 if (retval == bxattr_exit_ok) {
1161 jcr->xattr_data->nr_saved++;
1165 * For a soft linked file we are ready now, no need to recursively save the attributes.
1173 * See if this is the first real xattr being saved.
1174 * If it is save the toplevel_hidden_dir attributes first.
1175 * This is easy as its stored already in the jcr->xattr_data->content buffer.
1177 if (jcr->xattr_data->nr_saved == 0) {
1178 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1179 if (retval != bxattr_exit_ok) {
1182 jcr->xattr_data->nr_saved++;
1185 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1186 jcr->xattr_data->content_length = cnt;
1189 * Only dump the content of regular files.
1191 switch (st.st_mode & S_IFMT) {
1193 if (st.st_size > 0) {
1195 * Protect ourself against things getting out of hand.
1197 if (st.st_size >= MAX_XATTR_STREAM) {
1198 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1199 jcr->last_fname, MAX_XATTR_STREAM);
1203 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1204 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
1205 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
1206 jcr->xattr_data->content_length += cnt;
1210 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
1211 target_attrname, jcr->last_fname);
1212 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1213 target_attrname, jcr->last_fname);
1224 retval = send_xattr_stream(jcr, stream);
1225 if (retval == bxattr_exit_ok) {
1226 jcr->xattr_data->nr_saved++;
1231 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1232 * available on this extended attribute.
1235 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1238 * The recursive call could change our working dir so change back to the wanted workdir.
1240 if (fchdir(fd) < 0) {
1243 retval = bxattr_exit_ok;
1246 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1247 jcr->last_fname, be.bstrerror());
1248 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1249 jcr->last_fname, fd, be.bstrerror());
1265 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1268 int fd, filefd = -1, attrdirfd = -1;
1271 char current_xattr_namespace[PATH_MAX];
1272 bxattr_exit_code retval = bxattr_exit_error;
1276 * Determine what argument to use. Use attr_parent when set
1277 * (recursive call) or jcr->last_fname for first call. Also save
1278 * the current depth of the xattr_space we are in.
1282 if (xattr_namespace) {
1283 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1284 xattr_namespace, attr_parent);
1286 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1289 name = jcr->last_fname;
1290 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1294 * Open the file on which to save the xattrs read-only.
1296 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1299 retval = bxattr_exit_ok;
1302 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1303 jcr->last_fname, be.bstrerror());
1304 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1305 jcr->last_fname, be.bstrerror());
1311 * Open the xattr naming space.
1313 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1317 * Gentile way of the system saying this type of xattr layering is not supported.
1318 * Which is not problem we just forget about this this xattr.
1319 * But as this is not an error we return a positive return value.
1321 retval = bxattr_exit_ok;
1324 retval = bxattr_exit_ok;
1327 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1328 name, jcr->last_fname, be.bstrerror());
1329 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1330 name, jcr->last_fname, be.bstrerror());
1336 * We need to change into the attribute directory to determine if each of the
1337 * attributes should be saved.
1339 if (fchdir(attrdirfd) < 0) {
1340 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1341 jcr->last_fname, be.bstrerror());
1342 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1343 jcr->last_fname, attrdirfd, be.bstrerror());
1348 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1349 * else because the readdir returns "." entry after the extensible attr entry.
1350 * And as we want this entry before anything else we better just save its data.
1353 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1354 true, STREAM_XATTR_SOLARIS);
1356 if ((fd = dup(attrdirfd)) == -1 ||
1357 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1358 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1359 jcr->last_fname, be.bstrerror());
1360 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1361 jcr->last_fname, fd, be.bstrerror());
1367 * Walk the namespace.
1369 while (dp = readdir(dirp)) {
1371 * Skip only the toplevel . dir.
1373 if (!attr_parent && !strcmp(dp->d_name, "."))
1377 * Skip all .. directories
1379 if (!strcmp(dp->d_name, ".."))
1382 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1383 current_xattr_namespace, dp->d_name, jcr->last_fname);
1385 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1387 * We are not interested in read-only extensible attributes.
1389 if (!strcmp(dp->d_name, VIEW_READONLY)) {
1390 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1391 current_xattr_namespace, dp->d_name, jcr->last_fname);
1397 * We are only interested in read-write extensible attributes
1398 * when they contain non-transient values.
1400 if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1402 * Determine if there are non-transient system attributes at the toplevel.
1403 * We need to provide a fd to the open file.
1405 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1406 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1407 current_xattr_namespace, dp->d_name, jcr->last_fname);
1414 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1415 false, STREAM_XATTR_SOLARIS_SYS);
1418 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1423 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1424 false, STREAM_XATTR_SOLARIS);
1428 retval = bxattr_exit_ok;
1431 if (attrdirfd != -1)
1439 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1441 #ifdef HAVE_EXTENDED_ACL
1446 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1447 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
1449 return bxattr_exit_error;
1452 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1453 acl_set(attrname, aclp) != 0) {
1454 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1455 attrname, jcr->last_fname, be.bstrerror());
1456 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1457 attrname, jcr->last_fname, be.bstrerror());
1458 return bxattr_exit_error;
1464 return bxattr_exit_ok;
1466 #else /* HAVE_EXTENDED_ACL */
1468 aclent_t *acls = NULL;
1471 acls = aclfromtext(acl_text, &n);
1473 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1474 acl(attrname, SETACL, n, acls) != 0) {
1475 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1476 attrname, jcr->last_fname, be.bstrerror());
1477 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1478 attrname, jcr->last_fname, be.bstrerror());
1479 return bxattr_exit_error;
1486 return bxattr_exit_ok;
1488 #endif /* HAVE_EXTENDED_ACL */
1491 #endif /* HAVE_ACL */
1493 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1495 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1496 int used_bytes, total_bytes, cnt;
1497 char *bp, *target_attrname, *attribs;
1498 char *linked_target = NULL;
1499 char *acl_text = NULL;
1503 struct timeval times[2];
1504 bxattr_exit_code retval = bxattr_exit_error;
1508 * Parse the xattr stream. First the part that is the same for all xattrs.
1511 total_bytes = jcr->xattr_data->content_length;
1514 * The name of the target xattr has a leading / we are not interested
1515 * in that so skip it when decoding the string. We always start a the /
1516 * of the xattr space anyway.
1518 target_attrname = jcr->xattr_data->content + 1;
1519 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1520 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1526 * Open the file on which to restore the xattrs read-only.
1528 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1529 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1530 jcr->last_fname, be.bstrerror());
1531 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1532 jcr->last_fname, be.bstrerror());
1537 * Open the xattr naming space and make it the current working dir.
1539 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1540 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1541 jcr->last_fname, be.bstrerror());
1542 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1543 jcr->last_fname, be.bstrerror());
1547 if (fchdir(attrdirfd) < 0) {
1548 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1549 jcr->last_fname, be.bstrerror());
1550 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1551 jcr->last_fname, attrdirfd, be.bstrerror());
1556 * Try to open the correct xattr subdir based on the target_attrname given.
1557 * e.g. check if its a subdir attrname. Each / in the string makes us go
1560 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1563 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1564 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1565 target_attrname, jcr->last_fname, be.bstrerror());
1566 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1567 target_attrname, jcr->last_fname, be.bstrerror());
1575 * Open the xattr naming space.
1577 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1578 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1579 target_attrname, jcr->last_fname, be.bstrerror());
1580 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1581 target_attrname, jcr->last_fname, be.bstrerror());
1589 * Make the xattr space our current workingdir.
1591 if (fchdir(attrdirfd) < 0) {
1592 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1593 target_attrname, jcr->last_fname, be.bstrerror());
1594 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1595 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1599 target_attrname = ++bp;
1603 * Decode the attributes from the stream.
1605 decode_stat(attribs, &st, &inum);
1608 * Decode the next field (acl_text).
1610 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1611 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1617 * Based on the filetype perform the correct action. We support most filetypes here, more
1618 * then the actual implementation on Solaris supports so some code may never get executed
1619 * due to limitations in the implementation.
1621 switch (st.st_mode & S_IFMT) {
1624 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1626 unlinkat(attrdirfd, target_attrname, 0);
1627 if (mkfifo(target_attrname, st.st_mode) < 0) {
1628 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1629 target_attrname, jcr->last_fname, be.bstrerror());
1630 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1631 target_attrname, jcr->last_fname, be.bstrerror());
1638 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1640 unlinkat(attrdirfd, target_attrname, 0);
1641 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1642 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1643 target_attrname, jcr->last_fname, be.bstrerror());
1644 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1645 target_attrname, jcr->last_fname, be.bstrerror());
1651 * If its not the hidden_dir create the entry.
1652 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1654 if (strcmp(target_attrname, ".")) {
1655 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1656 if (mkdir(target_attrname, st.st_mode) < 0) {
1657 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1658 target_attrname, jcr->last_fname, be.bstrerror());
1659 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1660 target_attrname, jcr->last_fname, be.bstrerror());
1667 * See if this is a hard linked file. e.g. inum != 0
1672 unlinkat(attrdirfd, target_attrname, 0);
1673 if (link(linked_target, target_attrname) < 0) {
1674 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1675 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1676 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1677 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1682 * Successfully restored xattr.
1684 retval = bxattr_exit_ok;
1687 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1688 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
1692 if (used_bytes < (total_bytes - 1))
1696 * Restore the actual xattr.
1698 if (!is_extensible) {
1699 unlinkat(attrdirfd, target_attrname, 0);
1702 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1703 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1704 target_attrname, jcr->last_fname, be.bstrerror());
1705 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1706 target_attrname, jcr->last_fname, be.bstrerror());
1712 * Restore the actual data.
1714 if (st.st_size > 0) {
1715 used_bytes = (data - jcr->xattr_data->content);
1716 cnt = total_bytes - used_bytes;
1719 * Do a sanity check, the st.st_size should be the same as the number of bytes
1720 * we have available as data of the stream.
1722 if (cnt != st.st_size) {
1723 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
1724 target_attrname, jcr->last_fname);
1725 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1726 target_attrname, jcr->last_fname);
1731 cnt = write(attrfd, data, cnt);
1733 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
1734 target_attrname, jcr->last_fname, be.bstrerror());
1735 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
1736 target_attrname, jcr->last_fname, be.bstrerror());
1742 cnt = total_bytes - used_bytes;
1748 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1752 if (symlink(linked_target, target_attrname) < 0) {
1753 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
1754 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1755 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
1756 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1761 * Successfully restored xattr.
1763 retval = bxattr_exit_ok;
1770 * Restore owner and acl for non extensible attributes.
1772 if (!is_extensible) {
1773 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
1777 * Gentile way of the system saying this type of xattr layering is not supported.
1778 * But as this is not an error we return a positive return value.
1780 retval = bxattr_exit_ok;
1783 retval = bxattr_exit_ok;
1786 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1787 target_attrname, jcr->last_fname, be.bstrerror());
1788 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1789 target_attrname, jcr->last_fname, be.bstrerror());
1796 if (acl_text && *acl_text)
1797 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
1799 #endif /* HAVE_ACL */
1802 * For a non extensible attribute restore access and modification time on the xattr.
1804 if (!is_extensible) {
1805 times[0].tv_sec = st.st_atime;
1806 times[0].tv_usec = 0;
1807 times[1].tv_sec = st.st_mtime;
1808 times[1].tv_usec = 0;
1810 if (futimesat(attrdirfd, target_attrname, times) < 0) {
1811 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
1812 target_attrname, jcr->last_fname, be.bstrerror());
1813 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
1814 target_attrname, jcr->last_fname, be.bstrerror());
1820 * Successfully restored xattr.
1822 retval = bxattr_exit_ok;
1826 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
1828 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
1835 if (attrdirfd != -1) {
1844 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1847 bxattr_exit_code retval = bxattr_exit_ok;
1850 * First see if extended attributes or extensible attributes are present.
1851 * If not just pretend things went ok.
1853 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1854 jcr->xattr_data->nr_saved = 0;
1855 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
1858 * As we change the cwd in the save function save the current cwd
1859 * for restore after return from the solaris_save_xattrs function.
1861 getcwd(cwd, sizeof(cwd));
1862 retval = solaris_save_xattrs(jcr, NULL, NULL);
1864 delete jcr->xattr_data->link_cache;
1865 jcr->xattr_data->link_cache = NULL;
1870 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
1873 bool is_extensible = false;
1874 bxattr_exit_code retval;
1877 * First make sure we can restore xattr on the filesystem.
1880 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1881 case STREAM_XATTR_SOLARIS_SYS:
1882 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1883 Qmsg1(jcr, M_WARNING, 0,
1884 _("Failed to restore extensible attributes on file \"%s\"\n"),
1886 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1888 return bxattr_exit_error;
1891 is_extensible = true;
1894 case STREAM_XATTR_SOLARIS:
1895 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1896 Qmsg1(jcr, M_WARNING, 0,
1897 _("Failed to restore extended attributes on file \"%s\"\n"),
1899 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1901 return bxattr_exit_error;
1905 return bxattr_exit_error;
1909 * As we change the cwd in the restore function save the current cwd
1910 * for restore after return from the solaris_restore_xattrs function.
1912 getcwd(cwd, sizeof(cwd));
1913 retval = solaris_restore_xattrs(jcr, is_extensible);
1920 * Function pointers to the build and parse function to use for these xattrs.
1922 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
1923 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
1925 #endif /* defined(HAVE_SUN_OS) */
1928 * Entry points when compiled with support for XATTRs on a supported platform.
1930 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1932 if (os_build_xattr_streams) {
1933 return (*os_build_xattr_streams)(jcr, ff_pkt);
1935 return bxattr_exit_error;
1938 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
1942 if (os_parse_xattr_streams) {
1944 * See if we can parse this stream, and ifso give it a try.
1946 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
1947 if (os_default_xattr_streams[cnt] == stream) {
1948 return (*os_parse_xattr_streams)(jcr, stream);
1953 * Issue a warning and discard the message. But pretend the restore was ok.
1955 Jmsg2(jcr, M_WARNING, 0,
1956 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1957 jcr->last_fname, stream);
1958 return bxattr_exit_error;