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 * - Solaris (Extended Attributes and Extensible Attributes)
41 * Written by Marco van Wieringen, November MMVIII
48 #if !defined(HAVE_XATTR)
50 * Entry points when compiled without support for XATTRs or on an unsupported platform.
52 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
54 return bxattr_exit_fatal;
57 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
59 return bxattr_exit_fatal;
63 * Send a XATTR stream to the SD.
65 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
67 BSOCK *sd = jcr->store_bsock;
69 #ifdef FD_NO_SEND_TEST
70 return bxattr_exit_ok;
76 if (jcr->xattr_data->content_length <= 0) {
77 return bxattr_exit_ok;
83 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
84 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
86 return bxattr_exit_fatal;
90 * Send the buffer to the storage deamon
92 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
94 sd->msg = jcr->xattr_data->content;
95 sd->msglen = jcr->xattr_data->content_length;
99 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
101 return bxattr_exit_fatal;
104 jcr->JobBytes += sd->msglen;
106 if (!sd->signal(BNET_EOD)) {
107 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
109 return bxattr_exit_fatal;
111 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
112 return bxattr_exit_ok;
116 * This is a supported OS, See what kind of interface we should use.
117 * Start with the generic interface used by most OS-es.
119 #if defined(HAVE_DARWIN_OS) || \
120 defined(HAVE_LINUX_OS) || \
121 defined(HAVE_NETBSD_OS)
123 #ifdef HAVE_SYS_XATTR_H
124 #include <sys/xattr.h>
128 * Define the supported XATTR streams for this OS
130 #if defined(HAVE_DARWIN_OS)
131 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
132 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
133 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
134 #elif defined(HAVE_LINUX_OS)
135 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
136 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
137 static const char *xattr_skiplist[1] = { NULL };
138 #elif defined(HAVE_NETBSD_OS)
139 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
140 static const char *xattr_acl_skiplist[1] = { NULL };
141 static const char *xattr_skiplist[1] = { NULL };
145 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
146 * listxattr, getxattr and setxattr with an extra options argument
147 * which mimics the l variants of the functions when we specify
148 * XATTR_NOFOLLOW as the options value.
150 #if defined(HAVE_DARWIN_OS)
151 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
152 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
153 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
156 * Fallback to the non l-functions when those are not available.
158 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
159 #define lgetxattr getxattr
161 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
162 #define lsetxattr setxattr
164 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
165 #define llistxattr listxattr
169 static void xattr_drop_internal_table(xattr_t *xattr_value_list)
171 xattr_t *current_xattr;
174 * Walk the list of xattrs and free allocated memory on traversing.
176 for (current_xattr = xattr_value_list;
177 current_xattr != (xattr_t *)NULL;
180 * See if we can shortcut.
182 if (current_xattr->magic != XATTR_MAGIC)
185 free(current_xattr->name);
187 if (current_xattr->value_length > 0)
188 free(current_xattr->value);
192 * Free the array of control structs.
194 free(xattr_value_list);
198 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
199 * which encodes one or more xattr_t structures.
201 * The Serialized stream consists of the following elements:
202 * magic - A magic string which makes it easy to detect any binary incompatabilites
203 * name_length - The length of the following xattr name
204 * name - The name of the extended attribute
205 * value_length - The length of the following xattr data
206 * value - The actual content of the extended attribute
208 * This is repeated 1 or more times.
211 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list)
213 xattr_t *current_xattr;
217 * Make sure the serialized stream fits in the poolmem buffer.
218 * We allocate some more to be sure the stream is gonna fit.
220 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
221 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
224 * Walk the list of xattrs and serialize the data.
226 for (current_xattr = xattr_value_list; current_xattr != (xattr_t *)NULL; current_xattr++) {
228 * See if we can shortcut.
230 if (current_xattr->magic != XATTR_MAGIC)
233 ser_uint32(current_xattr->magic);
234 ser_uint32(current_xattr->name_length);
235 ser_bytes(current_xattr->name, current_xattr->name_length);
237 ser_uint32(current_xattr->value_length);
238 ser_bytes(current_xattr->value, current_xattr->value_length);
241 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
242 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
243 return jcr->xattr_data->content_length;
246 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
249 int cnt, xattr_count = 0;
250 int32_t xattr_list_len,
252 uint32_t expected_serialize_len = 0;
253 char *xattr_list, *bp;
254 xattr_t *xattr_value_list = NULL, *current_xattr;
255 bxattr_exit_code retval = bxattr_exit_error;
259 * First get the length of the available list with extended attributes.
261 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
262 if (xattr_list_len < 0) {
265 return bxattr_exit_ok;
267 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
268 jcr->last_fname, be.bstrerror());
269 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
270 jcr->last_fname, be.bstrerror());
271 return bxattr_exit_error;
273 } else if (xattr_list_len == 0) {
274 return bxattr_exit_ok;
278 * Allocate room for the extented attribute list.
280 xattr_list = (char *)malloc(xattr_list_len + 1);
281 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
284 * Get the actual list of extended attributes names for a file.
286 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
287 if (xattr_list_len < 0) {
290 retval = bxattr_exit_ok;
293 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
294 jcr->last_fname, be.bstrerror());
295 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
296 jcr->last_fname, be.bstrerror());
300 xattr_list[xattr_list_len] = '\0';
303 * Count the number of extended attributes on a file.
306 while ((bp - xattr_list) + 1 < xattr_list_len) {
310 * On some OSes you also get the acls in the extented attribute list.
311 * So we check if we are already backing up acls and if we do we
312 * don't store the extended attribute with the same info.
314 if (ff_pkt->flags & FO_ACL) {
315 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
316 if (!strcmp(bp, xattr_acl_skiplist[cnt])) {
324 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
327 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
328 if (!strcmp(bp, xattr_skiplist[cnt])) {
338 bp = strchr(bp, '\0') + 1;
341 if (xattr_count == 0) {
342 retval = bxattr_exit_ok;
347 * Allocate enough room to hold all extended attributes.
348 * After allocating the storage make sure its empty by zeroing it.
350 xattr_value_list = (xattr_t *)malloc(xattr_count * sizeof(xattr_t));
351 memset((caddr_t)xattr_value_list, 0, xattr_count * sizeof(xattr_t));
354 * Walk the list of extended attributes names and retrieve the data.
355 * We already count the bytes needed for serializing the stream later on.
357 current_xattr = xattr_value_list;
359 while ((bp - xattr_list) + 1 < xattr_list_len) {
363 * On some OSes you also get the acls in the extented attribute list.
364 * So we check if we are already backing up acls and if we do we
365 * don't store the extended attribute with the same info.
367 if (ff_pkt->flags & FO_ACL) {
368 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
369 if (!strcmp(bp, xattr_acl_skiplist[cnt])) {
377 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
380 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
381 if (!strcmp(bp, xattr_skiplist[cnt])) {
389 bp = strchr(bp, '\0') + 1;
394 * Each xattr valuepair starts with a magic so we can parse it easier.
396 current_xattr->magic = XATTR_MAGIC;
397 expected_serialize_len += sizeof(current_xattr->magic);
400 * Allocate space for storing the name.
402 current_xattr->name_length = strlen(bp);
403 current_xattr->name = (char *)malloc(current_xattr->name_length);
404 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
406 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
409 * First see how long the value is for the extended attribute.
411 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
412 if (xattr_value_len < 0) {
415 retval = bxattr_exit_ok;
418 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
419 jcr->last_fname, be.bstrerror());
420 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
421 jcr->last_fname, be.bstrerror());
427 * Allocate space for storing the value.
429 current_xattr->value = (char *)malloc(xattr_value_len);
430 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
432 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
433 if (xattr_value_len < 0) {
436 retval = bxattr_exit_ok;
439 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
440 jcr->last_fname, be.bstrerror());
441 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
442 jcr->last_fname, be.bstrerror());
448 * Store the actual length of the value.
450 current_xattr->value_length = xattr_value_len;
451 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
454 * Protect ourself against things getting out of hand.
456 if (expected_serialize_len >= MAX_XATTR_STREAM) {
457 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
458 jcr->last_fname, MAX_XATTR_STREAM);
466 bp = strchr(bp, '\0') + 1;
470 * Serialize the datastream.
472 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
473 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
475 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
480 xattr_drop_internal_table(xattr_value_list);
484 * Send the datastream to the SD.
486 return send_xattr_stream(jcr, os_default_xattr_streams[0]);
489 if (xattr_value_list) {
490 xattr_drop_internal_table(xattr_value_list);
496 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
499 xattr_t current_xattr;
500 bxattr_exit_code retval = bxattr_exit_ok;
504 * Parse the stream and perform the setxattr calls on the file.
506 * Start unserializing the data. We keep on looping while we have not
507 * unserialized all bytes in the stream.
509 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
510 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
512 * First make sure the magic is present. This way we can easily catch corruption.
513 * Any missing MAGIC is fatal we do NOT try to continue.
515 unser_uint32(current_xattr.magic);
516 if (current_xattr.magic != XATTR_MAGIC) {
517 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
519 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
521 return bxattr_exit_error;
525 * Decode the valuepair. First decode the length of the name.
527 unser_uint32(current_xattr.name_length);
530 * Allocate room for the name and decode its content.
532 current_xattr.name = (char *)malloc(current_xattr.name_length + 1);
533 unser_bytes(current_xattr.name, current_xattr.name_length);
536 * The xattr_name needs to be null terminated for lsetxattr.
538 current_xattr.name[current_xattr.name_length] = '\0';
541 * Decode the value length.
543 unser_uint32(current_xattr.value_length);
546 * Allocate room for the value and decode its content.
548 current_xattr.value = (char *)malloc(current_xattr.value_length);
549 unser_bytes(current_xattr.value, current_xattr.value_length);
552 * Try to set the extended attribute on the file.
553 * If we fail to set this attribute we flag the error but its not fatal,
554 * we try to restore the other extended attributes too.
556 if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
557 current_xattr.value_length, 0) != 0) {
562 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
563 jcr->last_fname, be.bstrerror());
564 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
565 jcr->last_fname, be.bstrerror());
566 retval = bxattr_exit_error;
572 * Free the temporary buffers.
574 free(current_xattr.name);
575 free(current_xattr.value);
578 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
583 * For all these os-es setup the build and parse function pointer to the generic functions.
585 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
586 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
588 #elif defined(HAVE_FREEBSD_OS)
590 #ifdef HAVE_SYS_EXTATTR_H
591 #include <sys/extattr.h>
594 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
595 static const char *xattr_acl_skiplist[1] = { NULL };
596 static const char *xattr_skiplist[1] = { NULL };
598 static bxattr_exit_code freebsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
600 bxattr_exit_code retval = bxattr_exit_ok;
605 static bxattr_exit_code freebsd_parse_xattr_streams(JCR *jcr, int stream)
607 bxattr_exit_code retval;
613 * Function pointers to the build and parse function to use for these xattrs.
615 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = freebsd_build_xattr_streams;
616 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = freebsd_parse_xattr_streams;
618 #elif defined(HAVE_SUN_OS)
620 * Solaris extended attributes were introduced in Solaris 9
623 * Solaris extensible attributes were introduced in OpenSolaris
624 * by PSARC 2007/315 Solaris extensible attributes are also
625 * sometimes called extended system attributes.
627 * man fsattr(5) on Solaris gives a wealth of info. The most
628 * important bits are:
630 * Attributes are logically supported as files within the file
631 * system. The file system is therefore augmented with an
632 * orthogonal name space of file attributes. Any file (includ-
633 * ing attribute files) can have an arbitrarily deep attribute
634 * tree associated with it. Attribute values are accessed by
635 * file descriptors obtained through a special attribute inter-
636 * face. This logical view of "attributes as files" allows the
637 * leveraging of existing file system interface functionality
638 * to support the construction, deletion, and manipulation of
641 * The special files "." and ".." retain their accustomed
642 * semantics within the attribute hierarchy. The "." attribute
643 * file refers to the current directory and the ".." attribute
644 * file refers to the parent directory. The unnamed directory
645 * at the head of each attribute tree is considered the "child"
646 * of the file it is associated with and the ".." file refers
647 * to the associated file. For any non-directory file with
648 * attributes, the ".." entry in the unnamed directory refers
649 * to a file that is not a directory.
651 * Conceptually, the attribute model is fully general. Extended
652 * attributes can be any type of file (doors, links, direc-
653 * tories, and so forth) and can even have their own attributes
654 * (fully recursive). As a result, the attributes associated
655 * with a file could be an arbitrarily deep directory hierarchy
656 * where each attribute could have an equally complex attribute
657 * tree associated with it. Not all implementations are able
658 * to, or want to, support the full model. Implementation are
659 * therefore permitted to reject operations that are not sup-
660 * ported. For example, the implementation for the UFS file
661 * system allows only regular files as attributes (for example,
662 * no sub-directories) and rejects attempts to place attributes
665 * The following list details the operations that are rejected
666 * in the current implementation:
668 * link Any attempt to create links between
669 * attribute and non-attribute space
670 * is rejected to prevent security-
671 * related or otherwise sensitive
672 * attributes from being exposed, and
673 * therefore manipulable, as regular
676 * rename Any attempt to rename between
677 * attribute and non-attribute space
678 * is rejected to prevent an already
679 * linked file from being renamed and
680 * thereby circumventing the link res-
683 * mkdir, symlink, mknod Any attempt to create a "non-
684 * regular" file in attribute space is
685 * rejected to reduce the functional-
686 * ity, and therefore exposure and
687 * risk, of the initial implementa-
690 * The entire available name space has been allocated to "gen-
691 * eral use" to bring the implementation in line with the NFSv4
692 * draft standard [NFSv4]. That standard defines "named attri-
693 * butes" (equivalent to Solaris Extended Attributes) with no
694 * naming restrictions. All Sun applications making use of
695 * opaque extended attributes will use the prefix "SUNW".
698 #ifdef HAVE_SYS_ATTR_H
699 #include <sys/attr.h>
706 #ifdef HAVE_SYS_NVPAIR_H
707 #include <sys/nvpair.h>
710 #ifdef HAVE_SYS_ACL_H
715 * Define the supported XATTR streams for this OS
717 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
718 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
720 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
721 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
724 * This code creates a temporary cache with entries for each xattr which has
725 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
727 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
729 xattr_link_cache_entry_t *ptr;
731 foreach_alist(ptr, jcr->xattr_data->link_cache) {
732 if (ptr && ptr->inum == inum) {
739 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
741 xattr_link_cache_entry_t *ptr;
743 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
744 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
746 bstrncpy(ptr->target, target, sizeof(ptr->target));
747 jcr->xattr_data->link_cache->append(ptr);
750 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
752 * This function returns true if a non default extended system attribute
753 * list is associated with fd and returns false when an error has occured
754 * or when only extended system attributes other than archive,
755 * av_modified or crtime are set.
757 * The function returns true for the following cases:
759 * - any extended system attribute other than the default attributes
760 * ('archive', 'av_modified' and 'crtime') is set
761 * - nvlist has NULL name string
762 * - nvpair has data type of 'nvlist'
763 * - default data type.
765 static bool solaris_has_non_transient_extensible_attributes(int fd)
775 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
780 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
781 name = nvpair_name(pair);
784 fattr = name_to_attr(name);
790 type = nvpair_type(pair);
792 case DATA_TYPE_BOOLEAN_VALUE:
793 if (nvpair_value_boolean_value(pair, &value) != 0) {
796 if (value && fattr != F_ARCHIVE &&
797 fattr != F_AV_MODIFIED) {
802 case DATA_TYPE_UINT64_ARRAY:
803 if (fattr != F_CRTIME) {
808 case DATA_TYPE_NVLIST:
816 if (response != NULL) {
817 nvlist_free(response);
821 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
823 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
825 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
826 * There is no need to store those acls as we already store the stat bits too.
828 static bool acl_is_trivial(int count, aclent_t *entries)
833 for (n = 0; n < count; n++) {
835 if (!(ace->a_type == USER_OBJ ||
836 ace->a_type == GROUP_OBJ ||
837 ace->a_type == OTHER_OBJ ||
838 ace->a_type == CLASS_OBJ))
843 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
845 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
848 #ifdef HAVE_EXTENDED_ACL
854 * See if this attribute has an ACL
856 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
857 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
859 * See if there is a non trivial acl on the file.
861 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
862 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
865 return bxattr_exit_ok;
867 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
868 attrname, jcr->last_fname, be.bstrerror());
869 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
870 attrname, jcr->last_fname, be.bstrerror());
871 return bxattr_exit_error;
876 #if defined(ACL_SID_FMT)
878 * New format flag added in newer Solaris versions.
880 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
882 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
883 #endif /* ACL_SID_FMT */
885 *acl_text = acl_totext(aclp, flags);
893 return bxattr_exit_ok;
894 #else /* HAVE_EXTENDED_ACL */
896 aclent_t *acls = NULL;
900 * See if this attribute has an ACL
903 n = facl(fd, GETACLCNT, 0, NULL);
905 n = acl(attrname, GETACLCNT, 0, NULL);
908 if (n >= MIN_ACL_ENTRIES) {
909 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
910 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
911 acl(attrname, GETACL, n, acls) != n) {
915 return bxattr_exit_ok;
917 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
918 attrname, jcr->last_fname, be.bstrerror());
919 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
920 attrname, jcr->last_fname, be.bstrerror());
922 return bxattr_exit_error;
927 * See if there is a non trivial acl on the file.
929 if (!acl_is_trivial(n, acls)) {
930 if ((*acl_text = acltotext(acls, n)) == NULL) {
931 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
932 attrname, jcr->last_fname, be.bstrerror());
933 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
934 attrname, jcr->last_fname, be.bstrerror());
936 return bxattr_exit_error;
946 return bxattr_exit_ok;
947 #endif /* HAVE_EXTENDED_ACL */
950 return bxattr_exit_ok;
951 #endif /* HAVE_ACL */
955 * Forward declaration for recursive function call.
957 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
960 * Save an extended or extensible attribute.
961 * This is stored as an opaque stream of bytes with the following encoding:
963 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
965 * or for a hardlinked or symlinked attribute
967 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
969 * xattr_name can be a subpath relative to the file the xattr is on.
970 * stat_buffer is the string representation of the stat struct.
971 * acl_string is an acl text when a non trivial acl is set on the xattr.
972 * actual_xattr_data is the content of the xattr file.
974 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
975 const char *attrname, bool toplevel_hidden_dir, int stream)
980 xattr_link_cache_entry_t *xlce;
981 char target_attrname[PATH_MAX];
982 char link_source[PATH_MAX];
983 char *acl_text = NULL;
984 char attribs[MAXSTRING];
986 bxattr_exit_code retval = bxattr_exit_error;
989 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
992 * Get the stats of the extended or extensible attribute.
994 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
997 retval = bxattr_exit_ok;
1000 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
1001 target_attrname, jcr->last_fname, be.bstrerror());
1002 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
1003 target_attrname, jcr->last_fname, be.bstrerror());
1009 * Based on the filetype perform the correct action. We support most filetypes here, more
1010 * then the actual implementation on Solaris supports so some code may never get executed
1011 * due to limitations in the implementation.
1013 switch (st.st_mode & S_IFMT) {
1018 * Get any acl on the xattr.
1020 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1024 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1025 * Encode the stat struct into an ASCII representation.
1027 encode_stat(attribs, &st, 0, stream);
1028 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
1029 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1033 * Get any acl on the xattr.
1035 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
1039 * See if this is the toplevel_hidden_dir being saved.
1041 if (toplevel_hidden_dir) {
1043 * Save the data for later storage when we encounter a real xattr. We store the data
1044 * in the jcr->xattr_data->content buffer and flush that just before sending out the
1045 * first real xattr. Encode the stat struct into an ASCII representation and jump
1046 * out of the function.
1048 encode_stat(attribs, &st, 0, stream);
1049 cnt = bsnprintf(buffer, sizeof(buffer),
1051 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1052 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1053 jcr->xattr_data->content_length = cnt;
1057 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1058 * Encode the stat struct into an ASCII representation.
1060 encode_stat(attribs, &st, 0, stream);
1061 cnt = bsnprintf(buffer, sizeof(buffer),
1063 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1068 * If this is a hardlinked file check the inode cache for a hit.
1070 if (st.st_nlink > 1) {
1072 * See if the cache already knows this inode number.
1074 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
1076 * Generate a xattr encoding with the reference to the target in there.
1078 encode_stat(attribs, &st, st.st_ino, stream);
1079 cnt = bsnprintf(buffer, sizeof(buffer),
1081 target_attrname, 0, attribs, 0, xlce->target, 0);
1082 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1083 jcr->xattr_data->content_length = cnt;
1084 retval = send_xattr_stream(jcr, stream);
1087 * For a hard linked file we are ready now, no need to recursively save the attributes.
1093 * Store this hard linked file in the cache.
1094 * Store the name relative to the top level xattr space.
1096 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
1100 * Get any acl on the xattr.
1102 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
1107 * Encode the stat struct into an ASCII representation.
1109 encode_stat(attribs, &st, 0, stream);
1110 cnt = bsnprintf(buffer, sizeof(buffer),
1112 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
1115 * Open the extended or extensible attribute file.
1117 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
1120 retval = bxattr_exit_ok;
1123 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
1124 target_attrname, jcr->last_fname, be.bstrerror());
1125 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
1126 target_attrname, jcr->last_fname, be.bstrerror());
1133 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1134 * Encode the stat struct into an ASCII representation.
1136 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
1139 retval = bxattr_exit_ok;
1142 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
1143 target_attrname, jcr->last_fname, be.bstrerror());
1144 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
1145 target_attrname, jcr->last_fname, be.bstrerror());
1151 * Generate a xattr encoding with the reference to the target in there.
1153 encode_stat(attribs, &st, st.st_ino, stream);
1154 cnt = bsnprintf(buffer, sizeof(buffer),
1156 target_attrname, 0, attribs, 0, link_source, 0);
1157 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1158 jcr->xattr_data->content_length = cnt;
1159 retval = send_xattr_stream(jcr, stream);
1161 if (retval == bxattr_exit_ok) {
1162 jcr->xattr_data->nr_saved++;
1166 * For a soft linked file we are ready now, no need to recursively save the attributes.
1174 * See if this is the first real xattr being saved.
1175 * If it is save the toplevel_hidden_dir attributes first.
1176 * This is easy as its stored already in the jcr->xattr_data->content buffer.
1178 if (jcr->xattr_data->nr_saved == 0) {
1179 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
1180 if (retval != bxattr_exit_ok) {
1183 jcr->xattr_data->nr_saved++;
1186 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
1187 jcr->xattr_data->content_length = cnt;
1190 * Only dump the content of regular files.
1192 switch (st.st_mode & S_IFMT) {
1194 if (st.st_size > 0) {
1196 * Protect ourself against things getting out of hand.
1198 if (st.st_size >= MAX_XATTR_STREAM) {
1199 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1200 jcr->last_fname, MAX_XATTR_STREAM);
1204 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
1205 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
1206 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
1207 jcr->xattr_data->content_length += cnt;
1211 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
1212 target_attrname, jcr->last_fname);
1213 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
1214 target_attrname, jcr->last_fname);
1225 retval = send_xattr_stream(jcr, stream);
1226 if (retval == bxattr_exit_ok) {
1227 jcr->xattr_data->nr_saved++;
1232 * Recursivly call solaris_save_extended_attributes for archiving the attributes
1233 * available on this extended attribute.
1236 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
1239 * The recursive call could change our working dir so change back to the wanted workdir.
1241 if (fchdir(fd) < 0) {
1244 retval = bxattr_exit_ok;
1247 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
1248 jcr->last_fname, be.bstrerror());
1249 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
1250 jcr->last_fname, fd, be.bstrerror());
1266 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
1269 int fd, filefd = -1, attrdirfd = -1;
1272 char current_xattr_namespace[PATH_MAX];
1273 bxattr_exit_code retval = bxattr_exit_error;
1277 * Determine what argument to use. Use attr_parent when set
1278 * (recursive call) or jcr->last_fname for first call. Also save
1279 * the current depth of the xattr_space we are in.
1283 if (xattr_namespace) {
1284 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
1285 xattr_namespace, attr_parent);
1287 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1290 name = jcr->last_fname;
1291 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
1295 * Open the file on which to save the xattrs read-only.
1297 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
1300 retval = bxattr_exit_ok;
1303 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1304 jcr->last_fname, be.bstrerror());
1305 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1306 jcr->last_fname, be.bstrerror());
1312 * Open the xattr naming space.
1314 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1318 * Gentile way of the system saying this type of xattr layering is not supported.
1319 * Which is not problem we just forget about this this xattr.
1320 * But as this is not an error we return a positive return value.
1322 retval = bxattr_exit_ok;
1325 retval = bxattr_exit_ok;
1328 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1329 name, jcr->last_fname, be.bstrerror());
1330 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1331 name, jcr->last_fname, be.bstrerror());
1337 * We need to change into the attribute directory to determine if each of the
1338 * attributes should be saved.
1340 if (fchdir(attrdirfd) < 0) {
1341 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1342 jcr->last_fname, be.bstrerror());
1343 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1344 jcr->last_fname, attrdirfd, be.bstrerror());
1349 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
1350 * else because the readdir returns "." entry after the extensible attr entry.
1351 * And as we want this entry before anything else we better just save its data.
1354 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
1355 true, STREAM_XATTR_SOLARIS);
1357 if ((fd = dup(attrdirfd)) == -1 ||
1358 (dirp = fdopendir(fd)) == (DIR *)NULL) {
1359 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
1360 jcr->last_fname, be.bstrerror());
1361 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
1362 jcr->last_fname, fd, be.bstrerror());
1368 * Walk the namespace.
1370 while (dp = readdir(dirp)) {
1372 * Skip only the toplevel . dir.
1374 if (!attr_parent && !strcmp(dp->d_name, "."))
1378 * Skip all .. directories
1380 if (!strcmp(dp->d_name, ".."))
1383 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
1384 current_xattr_namespace, dp->d_name, jcr->last_fname);
1386 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1388 * We are not interested in read-only extensible attributes.
1390 if (!strcmp(dp->d_name, VIEW_READONLY)) {
1391 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
1392 current_xattr_namespace, dp->d_name, jcr->last_fname);
1398 * We are only interested in read-write extensible attributes
1399 * when they contain non-transient values.
1401 if (!strcmp(dp->d_name, VIEW_READWRITE)) {
1403 * Determine if there are non-transient system attributes at the toplevel.
1404 * We need to provide a fd to the open file.
1406 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
1407 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
1408 current_xattr_namespace, dp->d_name, jcr->last_fname);
1415 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1416 false, STREAM_XATTR_SOLARIS_SYS);
1419 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
1424 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
1425 false, STREAM_XATTR_SOLARIS);
1429 retval = bxattr_exit_ok;
1432 if (attrdirfd != -1)
1440 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
1442 #ifdef HAVE_EXTENDED_ACL
1447 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
1448 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
1450 return bxattr_exit_error;
1453 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
1454 acl_set(attrname, aclp) != 0) {
1455 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1456 attrname, jcr->last_fname, be.bstrerror());
1457 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1458 attrname, jcr->last_fname, be.bstrerror());
1459 return bxattr_exit_error;
1465 return bxattr_exit_ok;
1467 #else /* HAVE_EXTENDED_ACL */
1469 aclent_t *acls = NULL;
1472 acls = aclfromtext(acl_text, &n);
1474 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
1475 acl(attrname, SETACL, n, acls) != 0) {
1476 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
1477 attrname, jcr->last_fname, be.bstrerror());
1478 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
1479 attrname, jcr->last_fname, be.bstrerror());
1480 return bxattr_exit_error;
1487 return bxattr_exit_ok;
1489 #endif /* HAVE_EXTENDED_ACL */
1492 #endif /* HAVE_ACL */
1494 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
1496 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
1497 int used_bytes, total_bytes, cnt;
1498 char *bp, *target_attrname, *attribs;
1499 char *linked_target = NULL;
1500 char *acl_text = NULL;
1504 struct timeval times[2];
1505 bxattr_exit_code retval = bxattr_exit_error;
1509 * Parse the xattr stream. First the part that is the same for all xattrs.
1512 total_bytes = jcr->xattr_data->content_length;
1515 * The name of the target xattr has a leading / we are not interested
1516 * in that so skip it when decoding the string. We always start a the /
1517 * of the xattr space anyway.
1519 target_attrname = jcr->xattr_data->content + 1;
1520 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
1521 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1527 * Open the file on which to restore the xattrs read-only.
1529 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
1530 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
1531 jcr->last_fname, be.bstrerror());
1532 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
1533 jcr->last_fname, be.bstrerror());
1538 * Open the xattr naming space and make it the current working dir.
1540 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1541 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
1542 jcr->last_fname, be.bstrerror());
1543 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
1544 jcr->last_fname, be.bstrerror());
1548 if (fchdir(attrdirfd) < 0) {
1549 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
1550 jcr->last_fname, be.bstrerror());
1551 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
1552 jcr->last_fname, attrdirfd, be.bstrerror());
1557 * Try to open the correct xattr subdir based on the target_attrname given.
1558 * e.g. check if its a subdir attrname. Each / in the string makes us go
1561 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
1564 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
1565 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1566 target_attrname, jcr->last_fname, be.bstrerror());
1567 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1568 target_attrname, jcr->last_fname, be.bstrerror());
1576 * Open the xattr naming space.
1578 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
1579 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
1580 target_attrname, jcr->last_fname, be.bstrerror());
1581 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
1582 target_attrname, jcr->last_fname, be.bstrerror());
1590 * Make the xattr space our current workingdir.
1592 if (fchdir(attrdirfd) < 0) {
1593 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
1594 target_attrname, jcr->last_fname, be.bstrerror());
1595 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
1596 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
1600 target_attrname = ++bp;
1604 * Decode the attributes from the stream.
1606 decode_stat(attribs, &st, &inum);
1609 * Decode the next field (acl_text).
1611 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
1612 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
1618 * Based on the filetype perform the correct action. We support most filetypes here, more
1619 * then the actual implementation on Solaris supports so some code may never get executed
1620 * due to limitations in the implementation.
1622 switch (st.st_mode & S_IFMT) {
1625 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1627 unlinkat(attrdirfd, target_attrname, 0);
1628 if (mkfifo(target_attrname, st.st_mode) < 0) {
1629 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
1630 target_attrname, jcr->last_fname, be.bstrerror());
1631 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
1632 target_attrname, jcr->last_fname, be.bstrerror());
1639 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1641 unlinkat(attrdirfd, target_attrname, 0);
1642 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
1643 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
1644 target_attrname, jcr->last_fname, be.bstrerror());
1645 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
1646 target_attrname, jcr->last_fname, be.bstrerror());
1652 * If its not the hidden_dir create the entry.
1653 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1655 if (strcmp(target_attrname, ".")) {
1656 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
1657 if (mkdir(target_attrname, st.st_mode) < 0) {
1658 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
1659 target_attrname, jcr->last_fname, be.bstrerror());
1660 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
1661 target_attrname, jcr->last_fname, be.bstrerror());
1668 * See if this is a hard linked file. e.g. inum != 0
1673 unlinkat(attrdirfd, target_attrname, 0);
1674 if (link(linked_target, target_attrname) < 0) {
1675 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
1676 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1677 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
1678 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1683 * Successfully restored xattr.
1685 retval = bxattr_exit_ok;
1688 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
1689 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
1693 if (used_bytes < (total_bytes - 1))
1697 * Restore the actual xattr.
1699 if (!is_extensible) {
1700 unlinkat(attrdirfd, target_attrname, 0);
1703 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
1704 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
1705 target_attrname, jcr->last_fname, be.bstrerror());
1706 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
1707 target_attrname, jcr->last_fname, be.bstrerror());
1713 * Restore the actual data.
1715 if (st.st_size > 0) {
1716 used_bytes = (data - jcr->xattr_data->content);
1717 cnt = total_bytes - used_bytes;
1720 * Do a sanity check, the st.st_size should be the same as the number of bytes
1721 * we have available as data of the stream.
1723 if (cnt != st.st_size) {
1724 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
1725 target_attrname, jcr->last_fname);
1726 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
1727 target_attrname, jcr->last_fname);
1732 cnt = write(attrfd, data, cnt);
1734 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
1735 target_attrname, jcr->last_fname, be.bstrerror());
1736 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
1737 target_attrname, jcr->last_fname, be.bstrerror());
1743 cnt = total_bytes - used_bytes;
1749 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
1753 if (symlink(linked_target, target_attrname) < 0) {
1754 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
1755 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1756 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
1757 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
1762 * Successfully restored xattr.
1764 retval = bxattr_exit_ok;
1771 * Restore owner and acl for non extensible attributes.
1773 if (!is_extensible) {
1774 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
1778 * Gentile way of the system saying this type of xattr layering is not supported.
1779 * But as this is not an error we return a positive return value.
1781 retval = bxattr_exit_ok;
1784 retval = bxattr_exit_ok;
1787 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
1788 target_attrname, jcr->last_fname, be.bstrerror());
1789 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
1790 target_attrname, jcr->last_fname, be.bstrerror());
1797 if (acl_text && *acl_text)
1798 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
1800 #endif /* HAVE_ACL */
1803 * For a non extensible attribute restore access and modification time on the xattr.
1805 if (!is_extensible) {
1806 times[0].tv_sec = st.st_atime;
1807 times[0].tv_usec = 0;
1808 times[1].tv_sec = st.st_mtime;
1809 times[1].tv_usec = 0;
1811 if (futimesat(attrdirfd, target_attrname, times) < 0) {
1812 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
1813 target_attrname, jcr->last_fname, be.bstrerror());
1814 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
1815 target_attrname, jcr->last_fname, be.bstrerror());
1821 * Successfully restored xattr.
1823 retval = bxattr_exit_ok;
1827 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
1829 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
1836 if (attrdirfd != -1) {
1845 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1848 bxattr_exit_code retval = bxattr_exit_ok;
1851 * First see if extended attributes or extensible attributes are present.
1852 * If not just pretend things went ok.
1854 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
1855 jcr->xattr_data->nr_saved = 0;
1856 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
1859 * As we change the cwd in the save function save the current cwd
1860 * for restore after return from the solaris_save_xattrs function.
1862 getcwd(cwd, sizeof(cwd));
1863 retval = solaris_save_xattrs(jcr, NULL, NULL);
1865 delete jcr->xattr_data->link_cache;
1866 jcr->xattr_data->link_cache = NULL;
1871 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
1874 bool is_extensible = false;
1875 bxattr_exit_code retval;
1878 * First make sure we can restore xattr on the filesystem.
1881 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
1882 case STREAM_XATTR_SOLARIS_SYS:
1883 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
1884 Qmsg1(jcr, M_WARNING, 0,
1885 _("Failed to restore extensible attributes on file \"%s\"\n"),
1887 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
1889 return bxattr_exit_error;
1892 is_extensible = true;
1895 case STREAM_XATTR_SOLARIS:
1896 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
1897 Qmsg1(jcr, M_WARNING, 0,
1898 _("Failed to restore extended attributes on file \"%s\"\n"),
1900 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
1902 return bxattr_exit_error;
1906 return bxattr_exit_error;
1910 * As we change the cwd in the restore function save the current cwd
1911 * for restore after return from the solaris_restore_xattrs function.
1913 getcwd(cwd, sizeof(cwd));
1914 retval = solaris_restore_xattrs(jcr, is_extensible);
1921 * Function pointers to the build and parse function to use for these xattrs.
1923 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
1924 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
1926 #endif /* defined(HAVE_SUN_OS) */
1929 * Entry points when compiled with support for XATTRs on a supported platform.
1931 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1933 if (os_build_xattr_streams) {
1934 return (*os_build_xattr_streams)(jcr, ff_pkt);
1936 return bxattr_exit_error;
1939 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
1943 if (os_parse_xattr_streams) {
1945 * See if we can parse this stream, and ifso give it a try.
1947 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
1948 if (os_default_xattr_streams[cnt] == stream) {
1949 return (*os_parse_xattr_streams)(jcr, stream);
1954 * Issue a warning and discard the message. But pretend the restore was ok.
1956 Jmsg2(jcr, M_WARNING, 0,
1957 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
1958 jcr->last_fname, stream);
1959 return bxattr_exit_error;