2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2010 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 three of the GNU Affero 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 Affero 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 * - AIX (Extended Attributes)
36 * - Darwin (Extended Attributes)
37 * - FreeBSD (Extended Attributes)
38 * - IRIX (Extended Attributes)
39 * - Linux (Extended Attributes)
40 * - NetBSD (Extended Attributes)
41 * - OpenBSD (Extended Attributes)
42 * (As it seems either they never implemented xattr or they are removed
43 * the support as it stated it was in version 3.1 but the current syscall
44 * tabled shows the extattr_ functions are not implemented. So as such we
45 * might eventually support xattr on OpenBSD when they implemented them using
46 * the same interface as FreeBSD and NetBSD.
47 * - Solaris (Extended Attributes and Extensible Attributes)
48 * - Tru64 (Extended Attributes)
50 * Written by Marco van Wieringen, November MMVIII
56 #if !defined(HAVE_XATTR)
58 * Entry points when compiled without support for XATTRs or on an unsupported platform.
60 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
62 return bxattr_exit_fatal;
65 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
67 return bxattr_exit_fatal;
71 * Send a XATTR stream to the SD.
73 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
75 BSOCK *sd = jcr->store_bsock;
77 #ifdef FD_NO_SEND_TEST
78 return bxattr_exit_ok;
84 if (jcr->xattr_data->content_length <= 0) {
85 return bxattr_exit_ok;
91 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
92 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
94 return bxattr_exit_fatal;
98 * Send the buffer to the storage deamon
100 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
102 sd->msg = jcr->xattr_data->content;
103 sd->msglen = jcr->xattr_data->content_length;
107 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
109 return bxattr_exit_fatal;
112 jcr->JobBytes += sd->msglen;
114 if (!sd->signal(BNET_EOD)) {
115 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
117 return bxattr_exit_fatal;
119 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
120 return bxattr_exit_ok;
124 * First some generic functions for OSes that use the same xattr encoding scheme.
125 * Currently for all OSes except for Solaris.
127 #if !defined(HAVE_SUN_OS)
128 static void xattr_drop_internal_table(alist *xattr_value_list)
130 xattr_t *current_xattr;
133 * Walk the list of xattrs and free allocated memory on traversing.
135 foreach_alist(current_xattr, xattr_value_list) {
137 * See if we can shortcut.
139 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
142 free(current_xattr->name);
144 if (current_xattr->value_length > 0)
145 free(current_xattr->value);
150 delete xattr_value_list;
154 * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
155 * which encodes one or more xattr_t structures.
157 * The Serialized stream consists of the following elements:
158 * magic - A magic string which makes it easy to detect any binary incompatabilites
159 * name_length - The length of the following xattr name
160 * name - The name of the extended attribute
161 * value_length - The length of the following xattr data
162 * value - The actual content of the extended attribute
164 * This is repeated 1 or more times.
167 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, alist *xattr_value_list)
169 xattr_t *current_xattr;
173 * Make sure the serialized stream fits in the poolmem buffer.
174 * We allocate some more to be sure the stream is gonna fit.
176 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
177 ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
180 * Walk the list of xattrs and serialize the data.
182 foreach_alist(current_xattr, xattr_value_list) {
184 * See if we can shortcut.
186 if (current_xattr == NULL || current_xattr->magic != XATTR_MAGIC)
189 ser_uint32(current_xattr->magic);
190 ser_uint32(current_xattr->name_length);
191 ser_bytes(current_xattr->name, current_xattr->name_length);
193 ser_uint32(current_xattr->value_length);
194 if (current_xattr->value_length > 0 && current_xattr->value) {
195 ser_bytes(current_xattr->value, current_xattr->value_length);
197 Dmsg3(100, "Backup xattr named %s, value %*s\n",
198 current_xattr->name, current_xattr->value, current_xattr->value);
200 Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
204 ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
205 jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
207 return jcr->xattr_data->content_length;
210 static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_list)
213 xattr_t *current_xattr;
214 bxattr_exit_code retval = bxattr_exit_ok;
217 * Parse the stream and call restore_xattr_on_file for each extended attribute.
219 * Start unserializing the data. We keep on looping while we have not
220 * unserialized all bytes in the stream.
222 unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
223 while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->content_length) {
225 * First make sure the magic is present. This way we can easily catch corruption.
226 * Any missing MAGIC is fatal we do NOT try to continue.
228 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
229 unser_uint32(current_xattr->magic);
230 if (current_xattr->magic != XATTR_MAGIC) {
231 Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
233 Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
236 return bxattr_exit_error;
240 * Decode the valuepair. First decode the length of the name.
242 unser_uint32(current_xattr->name_length);
243 if (current_xattr->name_length == 0) {
244 Mmsg1(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"),
246 Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n",
249 return bxattr_exit_error;
253 * Allocate room for the name and decode its content.
255 current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
256 unser_bytes(current_xattr->name, current_xattr->name_length);
259 * The xattr_name needs to be null terminated.
261 current_xattr->name[current_xattr->name_length] = '\0';
264 * Decode the value length.
266 unser_uint32(current_xattr->value_length);
268 if (current_xattr->value_length > 0) {
270 * Allocate room for the value and decode its content.
272 current_xattr->value = (char *)malloc(current_xattr->value_length);
273 unser_bytes(current_xattr->value, current_xattr->value_length);
275 Dmsg3(100, "Restoring xattr named %s, value %*s\n",
276 current_xattr->name, current_xattr->value, current_xattr->value);
278 current_xattr->value = NULL;
279 Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
282 xattr_value_list->append(current_xattr);
285 unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
291 * This is a supported OS, See what kind of interface we should use.
293 #if defined(HAVE_AIX_OS)
295 #if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
296 (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
297 (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
298 #error "Missing full support for the Extended Attributes (EA) functions."
304 #error "Missing sys/ea.h header file"
308 * Define the supported XATTR streams for this OS
310 static int os_default_xattr_streams[1] = { STREAM_XATTR_AIX };
313 * Fallback to the non l-functions when those are not available.
315 #if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
318 #if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
321 #if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
322 #define llistea listea
325 static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
328 char *xattr_list, *bp;
329 int cnt, xattr_count = 0;
330 uint32_t name_length;
331 int32_t xattr_list_len,
333 uint32_t expected_serialize_len = 0;
334 xattr_t *current_xattr = NULL;
335 alist *xattr_value_list = NULL;
336 bxattr_exit_code retval = bxattr_exit_error;
340 * First get the length of the available list with extended attributes.
342 xattr_list_len = llistea(jcr->last_fname, NULL, 0);
343 switch (xattr_list_len) {
349 return bxattr_exit_ok;
351 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
352 jcr->last_fname, be.bstrerror());
353 Dmsg2(100, "llistea error file=%s ERR=%s\n",
354 jcr->last_fname, be.bstrerror());
355 return bxattr_exit_error;
359 return bxattr_exit_ok;
365 * Allocate room for the extented attribute list.
367 xattr_list = (char *)malloc(xattr_list_len + 1);
368 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
371 * Get the actual list of extended attributes names for a file.
373 xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
374 switch (xattr_list_len) {
380 retval = bxattr_exit_ok;
383 Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
384 jcr->last_fname, be.bstrerror());
385 Dmsg2(100, "llistea error file=%s ERR=%s\n",
386 jcr->last_fname, be.bstrerror());
393 xattr_list[xattr_list_len] = '\0';
396 * Walk the list of extended attributes names and retrieve the data.
397 * We already count the bytes needed for serializing the stream later on.
400 while ((bp - xattr_list) + 1 < xattr_list_len) {
404 * We want to skip certain xattrs which start with a 0xF8 character on AIX.
410 name_length = strlen(bp);
411 if (skip_xattr || name_length == 0) {
412 Dmsg1(100, "Skipping xattr named %s\n", bp);
413 bp = strchr(bp, '\0') + 1;
418 * Each xattr valuepair starts with a magic so we can parse it easier.
420 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
421 current_xattr->magic = XATTR_MAGIC;
422 expected_serialize_len += sizeof(current_xattr->magic);
425 * Allocate space for storing the name.
427 current_xattr->name_length = name_length;
428 current_xattr->name = (char *)malloc(current_xattr->name_length);
429 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
431 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
434 * First see how long the value is for the extended attribute.
436 xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
437 switch (xattr_value_len) {
443 retval = bxattr_exit_ok;
446 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
447 jcr->last_fname, be.bstrerror());
448 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
449 jcr->last_fname, be.bstrerror());
454 current_xattr->value = NULL;
455 current_xattr->value_length = 0;
456 expected_serialize_len += sizeof(current_xattr->value_length);
460 * Allocate space for storing the value.
462 current_xattr->value = (char *)malloc(xattr_value_len);
463 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
465 xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
466 if (xattr_value_len < 0) {
471 retval = bxattr_exit_ok;
474 Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
475 jcr->last_fname, be.bstrerror());
476 Dmsg2(100, "lgetea error file=%s ERR=%s\n",
477 jcr->last_fname, be.bstrerror());
482 * Store the actual length of the value.
484 current_xattr->value_length = xattr_value_len;
485 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
488 * Protect ourself against things getting out of hand.
490 if (expected_serialize_len >= MAX_XATTR_STREAM) {
491 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
492 jcr->last_fname, MAX_XATTR_STREAM);
497 if (xattr_value_list == NULL) {
498 xattr_value_list = New(alist(10, not_owned_by_alist));
501 xattr_value_list->append(current_xattr);
502 current_xattr = NULL;
504 bp = strchr(bp, '\0') + 1;
509 xattr_list = (char *)NULL;
512 * If we found any xattr send them to the SD.
514 if (xattr_count > 0) {
516 * Serialize the datastream.
518 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
519 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
521 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
527 * Send the datastream to the SD.
529 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
531 retval = bxattr_exit_ok;
535 if (current_xattr != NULL) {
536 if (current_xattr->value != NULL) {
537 free(current_xattr->value);
539 if (current_xattr->name != NULL) {
540 free(current_xattr->name);
544 if (xattr_list != NULL) {
547 if (xattr_value_list != NULL) {
548 xattr_drop_internal_table(xattr_value_list);
553 static bxattr_exit_code aix_xattr_parse_streams(JCR *jcr, int stream)
555 xattr_t *current_xattr;
556 alist *xattr_value_list;
559 xattr_value_list = New(alist(10, not_owned_by_alist));
561 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
562 xattr_drop_internal_table(xattr_value_list);
563 return bxattr_exit_error;
566 foreach_alist(current_xattr, xattr_value_list) {
567 if (lsetea(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
574 Mmsg2(jcr->errmsg, _("lsetea error on file \"%s\": ERR=%s\n"),
575 jcr->last_fname, be.bstrerror());
576 Dmsg2(100, "lsetea error file=%s ERR=%s\n",
577 jcr->last_fname, be.bstrerror());
583 xattr_drop_internal_table(xattr_value_list);
584 return bxattr_exit_ok;
587 xattr_drop_internal_table(xattr_value_list);
588 return bxattr_exit_error;
592 * Function pointers to the build and parse function to use for these xattrs.
594 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_xattr_build_streams;
595 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = aix_xattr_parse_streams;
597 #elif defined(HAVE_IRIX_OS)
600 * Define the supported XATTR streams for this OS
602 static int os_default_xattr_streams[1] = { STREAM_XATTR_IRIX };
603 static const char *xattr_acl_skiplist[1] = { NULL };
604 static const char *xattr_skiplist[1] = { NULL };
606 struct xattr_naming_space {
611 static xattr_naming_space xattr_naming_spaces[] = {
612 { "user.", ATTR_DONTFOLLOW },
613 { "root.", ATTR_ROOT | ATTR_DONTFOLLOW },
617 static bxattr_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
619 int cnt, xattr_count = 0;
620 attrlist_cursor_t cursor;
621 attrlist_t *attrlist;
622 attrlist_ent_t *attrlist_ent;
623 xattr_t *current_xattr = NULL;
624 alist *xattr_value_list = NULL;
625 uint32_t expected_serialize_len = 0;
626 bxattr_exit_code retval = bxattr_exit_error;
627 POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
630 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
631 memset(cursor, 0, sizeof(attrlist_cursor_t));
633 if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
634 xattr_naming_spaces[cnt].flags, &cursor) != 0) {
637 retval = bxattr_exit_ok;
640 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
641 jcr->last_fname, be.bstrerror());
642 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
643 jcr->last_fname, be.bstrerror());
648 attrlist = (attrlist_t *)xattrbuf;
651 * Walk the available attributes.
653 for (cnt = 0; cnt < attrlist->al_count; cnt++) {
654 attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
657 * Each xattr valuepair starts with a magic so we can parse it easier.
659 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
660 current_xattr->magic = XATTR_MAGIC;
661 expected_serialize_len += sizeof(current_xattr->magic);
664 * Allocate space for storing the name.
665 * We store the name as <naming_space_name><xattr_name>
667 current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) + strlen(attrlist_ent->a_name) + 1;
668 current_xattr->name = (char *)malloc(current_xattr->name_length);
669 bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
670 xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
672 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
674 current_xattr->value_length = attrlist_ent->a_valuelen;
675 current_xattr->value = (char *)malloc(current_xattr->value_length);
678 * Retrieve the actual value of the xattr.
680 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
681 current_xattr->value_length, xattr_naming_spaces[cnt].flags) != 0) {
685 retval = bxattr_exit_ok;
689 * The buffer for the xattr isn't big enough. the value of
690 * current_xattr->value_length is updated with the actual size
691 * of the xattr. So we free the old buffer and create a new one
694 free(current_xattr->value);
695 current_xattr->value = (char *)malloc(current_xattr->value_length);
696 if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
697 current_xattr->value_length, xattr_naming_spaces[cnt].flags) != 0) {
701 retval = bxattr_exit_ok;
704 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
705 jcr->last_fname, be.bstrerror());
706 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
707 jcr->last_fname, be.bstrerror());
713 Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
714 jcr->last_fname, be.bstrerror());
715 Dmsg2(100, "attr_list error file=%s ERR=%s\n",
716 jcr->last_fname, be.bstrerror());
721 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
724 * Protect ourself against things getting out of hand.
726 if (expected_serialize_len >= MAX_XATTR_STREAM) {
727 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
728 jcr->last_fname, MAX_XATTR_STREAM);
732 if (xattr_value_list == NULL) {
733 xattr_value_list = New(alist(10, not_owned_by_alist));
736 xattr_value_list->append(current_xattr);
737 current_xattr = NULL;
742 * See if there are more attributes available for a next run of attr_list.
744 if (attrlist->al_more == 0) {
751 * If we found any xattr send them to the SD.
753 if (xattr_count > 0) {
755 * Serialize the datastream.
757 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
758 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
760 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
766 * Send the datastream to the SD.
768 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
770 retval = bxattr_exit_ok;
774 if (current_xattr != NULL) {
775 if (current_xattr->value != NULL) {
776 free(current_xattr->value);
778 if (current_xattr->name != NULL) {
779 free(current_xattr->name);
783 free_pool_memory(xattrbuf);
785 if (xattr_value_list != NULL) {
786 xattr_drop_internal_table(xattr_value_list);
791 static bxattr_exit_code irix_xattr_parse_streams(JCR *jcr, int stream)
794 int cnt, cmp_size, name_space_index;
795 xattr_t *current_xattr;
796 alist *xattr_value_list;
799 xattr_value_list = New(alist(10, not_owned_by_alist));
801 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
802 xattr_drop_internal_table(xattr_value_list);
803 return bxattr_exit_error;
806 foreach_alist(current_xattr, xattr_value_list) {
808 * See to what namingspace this xattr belongs to.
810 name_space_index = 0;
811 for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
812 cmp_size = strlen(xattr_naming_spaces[cnt].name);
813 if (!strncasecmp(current_xattr->name,
814 xattr_naming_spaces[cnt].name,
816 name_space_index = cnt;
822 * If we got a xattr that doesn't belong to an valid namespace complain.
824 if (name_space_index == 0) {
825 Mmsg2(jcr->errmsg, _("Received illegal xattr named %s on file \"%s\"\n"),
826 current_xattr->name, jcr->last_fname);
827 Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
828 current_xattr->name, jcr->last_fname);
833 * Restore the xattr first try to create the attribute from scratch.
835 flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
836 bp = strchr(current_xattr->name, '.');
837 if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
838 current_xattr->value_len, flags) != 0) {
841 retval = bxattr_exit_ok;
845 * The xattr already exists we need to replace it.
847 flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
848 if (attr_set(jcr->last_fname, bp, current_xattr->value,
849 current_xattr->value_len, flags) != 0) {
852 retval = bxattr_exit_ok;
855 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
856 jcr->last_fname, be.bstrerror());
857 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
858 jcr->last_fname, be.bstrerror());
864 Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
865 jcr->last_fname, be.bstrerror());
866 Dmsg2(100, "attr_set error file=%s ERR=%s\n",
867 jcr->last_fname, be.bstrerror());
873 xattr_drop_internal_table(xattr_value_list);
874 return bxattr_exit_ok;
877 xattr_drop_internal_table(xattr_value_list);
878 return bxattr_exit_error;
882 * Function pointers to the build and parse function to use for these xattrs.
884 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = irix_xattr_build_streams;
885 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = irix_xattr_parse_streams;
887 #elif defined(HAVE_DARWIN_OS) || \
888 defined(HAVE_LINUX_OS)
890 #if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
891 (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
892 (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
893 #error "Missing full support for the XATTR functions."
896 #ifdef HAVE_SYS_XATTR_H
897 #include <sys/xattr.h>
899 #error "Missing sys/xattr.h header file"
903 * Define the supported XATTR streams for this OS
905 #if defined(HAVE_DARWIN_OS)
906 static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
907 static const char *xattr_acl_skiplist[2] = { "com.apple.system.Security", NULL };
908 static const char *xattr_skiplist[3] = { "com.apple.system.extendedsecurity", "com.apple.ResourceFork", NULL };
909 #elif defined(HAVE_LINUX_OS)
910 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
911 static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
912 static const char *xattr_skiplist[1] = { NULL };
916 * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
917 * listxattr, getxattr and setxattr with an extra options argument
918 * which mimics the l variants of the functions when we specify
919 * XATTR_NOFOLLOW as the options value.
921 #if defined(HAVE_DARWIN_OS)
922 #define llistxattr(path, list, size) listxattr((path), (list), (size), XATTR_NOFOLLOW)
923 #define lgetxattr(path, name, value, size) getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
924 #define lsetxattr(path, name, value, size, flags) setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
927 * Fallback to the non l-functions when those are not available.
929 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
930 #define lgetxattr getxattr
932 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
933 #define lsetxattr setxattr
935 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
936 #define llistxattr listxattr
940 static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
943 char *xattr_list, *bp;
944 int cnt, xattr_count = 0;
945 uint32_t name_length;
946 int32_t xattr_list_len,
948 uint32_t expected_serialize_len = 0;
949 xattr_t *current_xattr = NULL;
950 alist *xattr_value_list = NULL;
951 bxattr_exit_code retval = bxattr_exit_error;
955 * First get the length of the available list with extended attributes.
957 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
958 switch (xattr_list_len) {
963 return bxattr_exit_ok;
965 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
966 jcr->last_fname, be.bstrerror());
967 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
968 jcr->last_fname, be.bstrerror());
969 return bxattr_exit_error;
973 return bxattr_exit_ok;
979 * Allocate room for the extented attribute list.
981 xattr_list = (char *)malloc(xattr_list_len + 1);
982 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
985 * Get the actual list of extended attributes names for a file.
987 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
988 switch (xattr_list_len) {
993 retval = bxattr_exit_ok;
996 Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
997 jcr->last_fname, be.bstrerror());
998 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
999 jcr->last_fname, be.bstrerror());
1006 xattr_list[xattr_list_len] = '\0';
1009 * Walk the list of extended attributes names and retrieve the data.
1010 * We already count the bytes needed for serializing the stream later on.
1013 while ((bp - xattr_list) + 1 < xattr_list_len) {
1017 * On some OSes you also get the acls in the extented attribute list.
1018 * So we check if we are already backing up acls and if we do we
1019 * don't store the extended attribute with the same info.
1021 if (ff_pkt->flags & FO_ACL) {
1022 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1023 if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
1031 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1034 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1035 if (bstrcmp(bp, xattr_skiplist[cnt])) {
1042 name_length = strlen(bp);
1043 if (skip_xattr || name_length == 0) {
1044 Dmsg1(100, "Skipping xattr named %s\n", bp);
1045 bp = strchr(bp, '\0') + 1;
1050 * Each xattr valuepair starts with a magic so we can parse it easier.
1052 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1053 current_xattr->magic = XATTR_MAGIC;
1054 expected_serialize_len += sizeof(current_xattr->magic);
1057 * Allocate space for storing the name.
1059 current_xattr->name_length = name_length;
1060 current_xattr->name = (char *)malloc(current_xattr->name_length);
1061 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
1063 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1066 * First see how long the value is for the extended attribute.
1068 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
1069 switch (xattr_value_len) {
1074 retval = bxattr_exit_ok;
1077 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1078 jcr->last_fname, be.bstrerror());
1079 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1080 jcr->last_fname, be.bstrerror());
1085 current_xattr->value = NULL;
1086 current_xattr->value_length = 0;
1087 expected_serialize_len += sizeof(current_xattr->value_length);
1091 * Allocate space for storing the value.
1093 current_xattr->value = (char *)malloc(xattr_value_len);
1094 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1096 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
1097 if (xattr_value_len < 0) {
1101 retval = bxattr_exit_ok;
1104 Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
1105 jcr->last_fname, be.bstrerror());
1106 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
1107 jcr->last_fname, be.bstrerror());
1112 * Store the actual length of the value.
1114 current_xattr->value_length = xattr_value_len;
1115 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1118 * Protect ourself against things getting out of hand.
1120 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1121 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1122 jcr->last_fname, MAX_XATTR_STREAM);
1127 if (xattr_value_list == NULL) {
1128 xattr_value_list = New(alist(10, not_owned_by_alist));
1131 xattr_value_list->append(current_xattr);
1132 current_xattr = NULL;
1134 bp = strchr(bp, '\0') + 1;
1139 xattr_list = (char *)NULL;
1142 * If we found any xattr send them to the SD.
1144 if (xattr_count > 0) {
1146 * Serialize the datastream.
1148 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1149 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1151 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1157 * Send the datastream to the SD.
1159 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1161 retval = bxattr_exit_ok;
1165 if (current_xattr != NULL) {
1166 if (current_xattr->value != NULL) {
1167 free(current_xattr->value);
1169 if (current_xattr->name != NULL) {
1170 free(current_xattr->name);
1172 free(current_xattr);
1174 if (xattr_list != NULL) {
1177 if (xattr_value_list != NULL) {
1178 xattr_drop_internal_table(xattr_value_list);
1183 static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
1185 xattr_t *current_xattr;
1186 alist *xattr_value_list;
1189 xattr_value_list = New(alist(10, not_owned_by_alist));
1191 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1192 xattr_drop_internal_table(xattr_value_list);
1193 return bxattr_exit_error;
1196 foreach_alist(current_xattr, xattr_value_list) {
1197 if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
1203 Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
1204 jcr->last_fname, be.bstrerror());
1205 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
1206 jcr->last_fname, be.bstrerror());
1212 xattr_drop_internal_table(xattr_value_list);
1213 return bxattr_exit_ok;
1216 xattr_drop_internal_table(xattr_value_list);
1217 return bxattr_exit_error;
1221 * Function pointers to the build and parse function to use for these xattrs.
1223 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
1224 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
1226 #elif defined(HAVE_FREEBSD_OS) || \
1227 defined(HAVE_NETBSD_OS) || \
1228 defined(HAVE_OPENBSD_OS)
1230 #if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
1231 (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
1232 (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
1233 !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
1234 !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
1235 #error "Missing full support for the extattr functions."
1238 #ifdef HAVE_SYS_EXTATTR_H
1239 #include <sys/extattr.h>
1241 #error "Missing sys/extattr.h header file"
1244 #ifdef HAVE_LIBUTIL_H
1245 #include <libutil.h>
1248 #if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
1249 #define extattr_get_link extattr_get_file
1251 #if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
1252 #define extattr_set_link extattr_set_file
1254 #if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
1255 #define extattr_list_link extattr_list_file
1258 #if defined(HAVE_FREEBSD_OS)
1259 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
1260 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1261 static const char *xattr_acl_skiplist[2] = { "system.posix1e.acl_access", NULL };
1262 static const char *xattr_skiplist[1] = { NULL };
1263 #elif defined(HAVE_NETBSD_OS)
1264 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
1265 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1266 static const char *xattr_acl_skiplist[1] = { NULL };
1267 static const char *xattr_skiplist[1] = { NULL };
1268 #elif defined(HAVE_OPENBSD_OS)
1269 static int os_default_xattr_streams[1] = { STREAM_XATTR_OPENBSD };
1270 static int os_default_xattr_namespaces[2] = { EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM };
1271 static const char *xattr_acl_skiplist[1] = { NULL };
1272 static const char *xattr_skiplist[1] = { NULL };
1275 static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1279 int cnt, index, xattr_count = 0;
1280 int32_t xattr_list_len,
1282 uint32_t expected_serialize_len = 0;
1283 unsigned int namespace_index;
1285 char *current_attrnamespace = NULL;
1286 char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
1287 xattr_t *current_xattr = NULL;
1288 alist *xattr_value_list = NULL;
1289 bxattr_exit_code retval = bxattr_exit_error;
1293 * Loop over all available xattr namespaces.
1295 for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
1296 attrnamespace = os_default_xattr_namespaces[namespace_index];
1299 * Convert the numeric attrnamespace into a string representation and make a private copy of that string.
1300 * The extattr_namespace_to_string functions returns a strdupped string which we need to free.
1302 if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
1303 Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
1304 attrnamespace, jcr->last_fname);
1305 Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n",
1306 attrnamespace, jcr->last_fname);
1311 * First get the length of the available list with extended attributes.
1312 * If we get EPERM on system namespace, don't return error.
1313 * This is expected for normal users trying to archive the system
1314 * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
1315 * they've decided to return EOPNOTSUPP instead.
1317 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
1318 switch (xattr_list_len) {
1322 retval = bxattr_exit_ok;
1324 #if defined(EOPNOTSUPP)
1328 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
1329 actuallyfree(current_attrnamespace);
1330 current_attrnamespace = NULL;
1337 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1338 jcr->last_fname, be.bstrerror());
1339 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1340 jcr->last_fname, be.bstrerror());
1351 * Allocate room for the extented attribute list.
1353 xattr_list = (char *)malloc(xattr_list_len + 1);
1354 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
1357 * Get the actual list of extended attributes names for a file.
1359 xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, xattr_list, xattr_list_len);
1360 switch (xattr_list_len) {
1364 retval = bxattr_exit_ok;
1367 Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
1368 jcr->last_fname, be.bstrerror());
1369 Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n",
1370 jcr->last_fname, be.bstrerror());
1377 xattr_list[xattr_list_len] = '\0';
1380 * Walk the list of extended attributes names and retrieve the data.
1381 * We already count the bytes needed for serializing the stream later on.
1383 for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
1387 * Print the current name into the buffer as its not null terminated we need to
1388 * use the length encoded in the string for copying only the needed bytes.
1390 cnt = xattr_list[index];
1391 if (cnt > ((int)sizeof(current_attrname) - 1)) {
1392 cnt = ((int)sizeof(current_attrname) - 1);
1394 strncpy(current_attrname, xattr_list + (index + 1), cnt);
1395 current_attrname[cnt] = '\0';
1398 * First make a xattr tuple of the current namespace and the name of the xattr.
1399 * e.g. something like user.<attrname> or system.<attrname>
1401 bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s", current_attrnamespace, current_attrname);
1404 * On some OSes you also get the acls in the extented attribute list.
1405 * So we check if we are already backing up acls and if we do we
1406 * don't store the extended attribute with the same info.
1408 if (ff_pkt->flags & FO_ACL) {
1409 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1410 if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
1418 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1421 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1422 if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
1430 Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
1435 * Each xattr valuepair starts with a magic so we can parse it easier.
1437 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1438 current_xattr->magic = XATTR_MAGIC;
1439 expected_serialize_len += sizeof(current_xattr->magic);
1442 * Allocate space for storing the name.
1444 current_xattr->name_length = strlen(current_attrtuple);
1445 current_xattr->name = (char *)malloc(current_xattr->name_length);
1446 memcpy((caddr_t)current_xattr->name, (caddr_t)current_attrtuple, current_xattr->name_length);
1448 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1451 * First see how long the value is for the extended attribute.
1453 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
1454 switch (xattr_value_len) {
1458 retval = bxattr_exit_ok;
1461 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1462 jcr->last_fname, be.bstrerror());
1463 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1464 jcr->last_fname, be.bstrerror());
1469 current_xattr->value = NULL;
1470 current_xattr->value_length = 0;
1471 expected_serialize_len += sizeof(current_xattr->value_length);
1475 * Allocate space for storing the value.
1477 current_xattr->value = (char *)malloc(xattr_value_len);
1478 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
1480 xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, current_xattr->value, xattr_value_len);
1481 if (xattr_value_len < 0) {
1484 retval = bxattr_exit_ok;
1487 Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
1488 jcr->last_fname, be.bstrerror());
1489 Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n",
1490 jcr->last_fname, be.bstrerror());
1496 * Store the actual length of the value.
1498 current_xattr->value_length = xattr_value_len;
1499 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1502 * Protect ourself against things getting out of hand.
1504 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1505 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1506 jcr->last_fname, MAX_XATTR_STREAM);
1512 if (xattr_value_list == NULL) {
1513 xattr_value_list = New(alist(10, not_owned_by_alist));
1516 xattr_value_list->append(current_xattr);
1517 current_xattr = NULL;
1523 * Drop the local copy of the current_attrnamespace.
1525 actuallyfree(current_attrnamespace);
1526 current_attrnamespace = NULL;
1529 * We are done with this xattr list.
1532 xattr_list = (char *)NULL;
1536 * If we found any xattr send them to the SD.
1538 if (xattr_count > 0) {
1540 * Serialize the datastream.
1542 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1543 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1545 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1551 * Send the datastream to the SD.
1553 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1555 retval = bxattr_exit_ok;
1559 if (current_attrnamespace != NULL) {
1560 actuallyfree(current_attrnamespace);
1562 if (current_xattr != NULL) {
1563 if (current_xattr->value != NULL) {
1564 free(current_xattr->value);
1566 if (current_xattr->name != NULL) {
1567 free(current_xattr->name);
1569 free(current_xattr);
1571 if (xattr_list != NULL) {
1574 if (xattr_value_list != NULL) {
1575 xattr_drop_internal_table(xattr_value_list);
1580 static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
1582 xattr_t *current_xattr;
1583 alist *xattr_value_list;
1584 int current_attrnamespace, cnt;
1585 char *attrnamespace, *attrname;
1588 xattr_value_list = New(alist(10, not_owned_by_alist));
1590 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1591 xattr_drop_internal_table(xattr_value_list);
1592 return bxattr_exit_error;
1595 foreach_alist(current_xattr, xattr_value_list) {
1597 * Try splitting the xattr_name into a namespace and name part.
1598 * The splitting character is a .
1600 attrnamespace = current_xattr->name;
1601 if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
1602 Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
1603 current_xattr->name, jcr->last_fname);
1604 Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n",
1605 current_xattr->name, jcr->last_fname);
1611 * Make sure the attrnamespace makes sense.
1613 if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
1614 Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
1615 attrnamespace, jcr->last_fname);
1616 Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n",
1617 attrnamespace, jcr->last_fname);
1622 * Try restoring the extended attribute.
1624 cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
1625 attrname, current_xattr->value, current_xattr->value_length);
1626 if (cnt < 0 || cnt != (int)current_xattr->value_length) {
1632 Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
1633 jcr->last_fname, be.bstrerror());
1634 Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n",
1635 jcr->last_fname, be.bstrerror());
1642 xattr_drop_internal_table(xattr_value_list);
1643 return bxattr_exit_ok;
1646 xattr_drop_internal_table(xattr_value_list);
1647 return bxattr_exit_error;
1651 * Function pointers to the build and parse function to use for these xattrs.
1653 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
1654 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
1656 #elif defined(HAVE_OSF1_OS)
1658 #if !defined(HAVE_GETPROPLIST) || \
1659 !defined(HAVE_GET_PROPLIST_ENTRY) || \
1660 !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
1661 !defined(HAVE_ADD_PROPLIST_ENTRY) || \
1662 !defined(HAVE_SETPROPLIST)
1663 #error "Missing full support for the Extended Attributes functions."
1666 #ifdef HAVE_SYS_PROPLIST_H
1667 #include <sys/proplist.h>
1669 #error "Missing sys/proplist.h header file"
1673 * Define the supported XATTR streams for this OS
1675 static int os_default_xattr_streams[1] = { STREAM_XATTR_TRU64 };
1676 static const char *xattr_acl_skiplist[1] = { NULL };
1677 static const char *xattr_skiplist[1] = { NULL };
1679 static bxattr_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
1685 int xattr_count = 0;
1688 int32_t xattr_list_len,
1691 uint32_t expected_serialize_len = 0;
1692 xattr_t *current_xattr = NULL;
1693 alist *xattr_value_list = NULL;
1694 struct proplistname_args prop_args;
1695 bxattr_exit_code retval = bxattr_exit_error;
1696 POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
1699 xattrbuf_size = sizeof_pool_memory(xattrbuf);
1700 xattrbuf_min_size = 0;
1701 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1702 xattrbuf, &xattrbuf_min_size);
1705 * See what xattr are available.
1707 switch (xattr_list_len) {
1711 retval = bacl_exit_ok;
1714 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1715 jcr->last_fname, be.bstrerror());
1716 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1717 jcr->last_fname, be.bstrerror());
1722 if (xattrbuf_min_size) {
1724 * The buffer isn't big enough to hold the xattr data, we now have
1725 * a minimum buffersize so we resize the buffer and try again.
1727 xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
1728 xattrbuf_size = xattrbuf_min_size + 1;
1729 xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
1730 xattrbuf, &xattrbuf_min_size);
1731 switch (xattr_list_len) {
1735 retval = bacl_exit_ok;
1738 Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
1739 jcr->last_fname, be.bstrerror());
1740 Dmsg2(100, "getproplist error file=%s ERR=%s\n",
1741 jcr->last_fname, be.bstrerror());
1747 * This should never happen as we sized the buffer according to the minimumsize
1748 * returned by a previous getproplist call. If it does happen things are fishy and
1749 * we are better of forgetting this xattr as it seems its list is changing at this
1750 * exact moment so we can never make a good backup copy of it.
1752 retval = bacl_exit_ok;
1761 retval = bacl_exit_ok;
1770 * Walk the list of extended attributes names and retrieve the data.
1771 * We already count the bytes needed for serializing the stream later on.
1774 while (xattrbuf_size > 0) {
1776 * Call getproplist_entry to initialize name and value
1777 * pointers to entries position within buffer.
1779 xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
1782 * On some OSes you also get the acls in the extented attribute list.
1783 * So we check if we are already backing up acls and if we do we
1784 * don't store the extended attribute with the same info.
1786 if (ff_pkt->flags & FO_ACL) {
1787 for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
1788 if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
1796 * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
1799 for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
1800 if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
1808 Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
1813 * Each xattr valuepair starts with a magic so we can parse it easier.
1815 current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
1816 current_xattr->magic = XATTR_MAGIC;
1817 expected_serialize_len += sizeof(current_xattr->magic);
1819 current_xattr->name_length = strlen(xattr_name);
1820 current_xattr->name = bstrdup(xattr_name);
1822 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
1824 current_xattr->value_length = *xattr_value_len;
1825 current_xattr->value = (char *)malloc(current_xattr->value_length);
1826 memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
1828 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
1831 * Protect ourself against things getting out of hand.
1833 if (expected_serialize_len >= MAX_XATTR_STREAM) {
1834 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
1835 jcr->last_fname, MAX_XATTR_STREAM);
1839 if (xattr_value_list == NULL) {
1840 xattr_value_list = New(alist(10, not_owned_by_alist));
1843 xattr_value_list->append(current_xattr);
1844 current_xattr = NULL;
1849 * If we found any xattr send them to the SD.
1851 if (xattr_count > 0) {
1853 * Serialize the datastream.
1855 if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
1856 Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
1858 Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
1864 * Send the datastream to the SD.
1866 retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
1870 if (current_xattr != NULL) {
1871 if (current_xattr->value != NULL) {
1872 free(current_xattr->value);
1874 if (current_xattr->name != NULL) {
1875 free(current_xattr->name);
1877 free(current_xattr);
1879 if (xattr_value_list != NULL) {
1880 xattr_drop_internal_table(xattr_value_list);
1882 free_pool_memory(xattrbuf);
1887 static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr, int stream)
1889 char *bp, *xattrbuf = NULL;
1890 int32_t xattrbuf_size, cnt;
1891 xattr_t *current_xattr;
1892 alist *xattr_value_list;
1895 xattr_value_list = New(alist(10, not_owned_by_alist));
1897 if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
1898 xattr_drop_internal_table(xattr_value_list);
1899 return bxattr_exit_error;
1903 * See how big the propertylist must be.
1906 foreach_alist(current_xattr, xattr_value_list) {
1907 xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
1910 xattrbuf = (char *)malloc(xattrbuf_size);
1913 * Add all value pairs to the proplist.
1917 foreach_alist(current_xattr, xattr_value_list) {
1918 cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
1919 current_xattr->value, &bp);
1925 if (cnt != xattrbuf_size) {
1926 Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
1928 Dmsg1(100, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
1934 * Restore the list of extended attributes on the file.
1936 cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
1941 retval = bacl_exit_ok;
1944 Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
1945 jcr->last_fname, be.bstrerror());
1946 Dmsg2(100, "setproplist error file=%s ERR=%s\n",
1947 jcr->last_fname, be.bstrerror());
1957 xattr_drop_internal_table(xattr_value_list);
1958 return bxattr_exit_ok;
1964 xattr_drop_internal_table(xattr_value_list);
1965 return bxattr_exit_error;
1969 * Function pointers to the build and parse function to use for these xattrs.
1971 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_xattr_streams;
1972 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = tru64_parse_xattr_streams;
1974 #elif defined(HAVE_SUN_OS)
1976 * Solaris extended attributes were introduced in Solaris 9
1979 * Solaris extensible attributes were introduced in OpenSolaris
1980 * by PSARC 2007/315 Solaris extensible attributes are also
1981 * sometimes called extended system attributes.
1983 * man fsattr(5) on Solaris gives a wealth of info. The most
1984 * important bits are:
1986 * Attributes are logically supported as files within the file
1987 * system. The file system is therefore augmented with an
1988 * orthogonal name space of file attributes. Any file (includ-
1989 * ing attribute files) can have an arbitrarily deep attribute
1990 * tree associated with it. Attribute values are accessed by
1991 * file descriptors obtained through a special attribute inter-
1992 * face. This logical view of "attributes as files" allows the
1993 * leveraging of existing file system interface functionality
1994 * to support the construction, deletion, and manipulation of
1997 * The special files "." and ".." retain their accustomed
1998 * semantics within the attribute hierarchy. The "." attribute
1999 * file refers to the current directory and the ".." attribute
2000 * file refers to the parent directory. The unnamed directory
2001 * at the head of each attribute tree is considered the "child"
2002 * of the file it is associated with and the ".." file refers
2003 * to the associated file. For any non-directory file with
2004 * attributes, the ".." entry in the unnamed directory refers
2005 * to a file that is not a directory.
2007 * Conceptually, the attribute model is fully general. Extended
2008 * attributes can be any type of file (doors, links, direc-
2009 * tories, and so forth) and can even have their own attributes
2010 * (fully recursive). As a result, the attributes associated
2011 * with a file could be an arbitrarily deep directory hierarchy
2012 * where each attribute could have an equally complex attribute
2013 * tree associated with it. Not all implementations are able
2014 * to, or want to, support the full model. Implementation are
2015 * therefore permitted to reject operations that are not sup-
2016 * ported. For example, the implementation for the UFS file
2017 * system allows only regular files as attributes (for example,
2018 * no sub-directories) and rejects attempts to place attributes
2021 * The following list details the operations that are rejected
2022 * in the current implementation:
2024 * link Any attempt to create links between
2025 * attribute and non-attribute space
2026 * is rejected to prevent security-
2027 * related or otherwise sensitive
2028 * attributes from being exposed, and
2029 * therefore manipulable, as regular
2032 * rename Any attempt to rename between
2033 * attribute and non-attribute space
2034 * is rejected to prevent an already
2035 * linked file from being renamed and
2036 * thereby circumventing the link res-
2039 * mkdir, symlink, mknod Any attempt to create a "non-
2040 * regular" file in attribute space is
2041 * rejected to reduce the functional-
2042 * ity, and therefore exposure and
2043 * risk, of the initial implementa-
2046 * The entire available name space has been allocated to "gen-
2047 * eral use" to bring the implementation in line with the NFSv4
2048 * draft standard [NFSv4]. That standard defines "named attri-
2049 * butes" (equivalent to Solaris Extended Attributes) with no
2050 * naming restrictions. All Sun applications making use of
2051 * opaque extended attributes will use the prefix "SUNW".
2054 #ifdef HAVE_SYS_ATTR_H
2055 #include <sys/attr.h>
2062 #ifdef HAVE_SYS_NVPAIR_H
2063 #include <sys/nvpair.h>
2066 #ifdef HAVE_SYS_ACL_H
2067 #include <sys/acl.h>
2070 #if !defined(HAVE_OPENAT) || \
2071 !defined(HAVE_UNLINKAT) || \
2072 !defined(HAVE_FCHOWNAT) || \
2073 !defined(HAVE_FUTIMESAT)
2074 #error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
2078 * Define the supported XATTR streams for this OS
2080 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2081 static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
2083 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
2084 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
2087 * This code creates a temporary cache with entries for each xattr which has
2088 * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
2090 static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
2092 xattr_link_cache_entry_t *ptr;
2094 foreach_alist(ptr, jcr->xattr_data->link_cache) {
2095 if (ptr && ptr->inum == inum) {
2102 static void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
2104 xattr_link_cache_entry_t *ptr;
2106 ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
2107 memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
2109 bstrncpy(ptr->target, target, sizeof(ptr->target));
2110 jcr->xattr_data->link_cache->append(ptr);
2113 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2115 * This function returns true if a non default extended system attribute
2116 * list is associated with fd and returns false when an error has occured
2117 * or when only extended system attributes other than archive,
2118 * av_modified or crtime are set.
2120 * The function returns true for the following cases:
2122 * - any extended system attribute other than the default attributes
2123 * ('archive', 'av_modified' and 'crtime') is set
2124 * - nvlist has NULL name string
2125 * - nvpair has data type of 'nvlist'
2126 * - default data type.
2128 static bool solaris_has_non_transient_extensible_attributes(int fd)
2136 bool retval = false;
2138 if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
2143 while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
2144 name = nvpair_name(pair);
2147 fattr = name_to_attr(name);
2153 type = nvpair_type(pair);
2155 case DATA_TYPE_BOOLEAN_VALUE:
2156 if (nvpair_value_boolean_value(pair, &value) != 0) {
2159 if (value && fattr != F_ARCHIVE &&
2160 fattr != F_AV_MODIFIED) {
2165 case DATA_TYPE_UINT64_ARRAY:
2166 if (fattr != F_CRTIME) {
2171 case DATA_TYPE_NVLIST:
2179 if (response != NULL) {
2180 nvlist_free(response);
2184 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2186 #if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
2188 * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
2189 * There is no need to store those acls as we already store the stat bits too.
2191 static bool acl_is_trivial(int count, aclent_t *entries)
2196 for (n = 0; n < count; n++) {
2198 if (!(ace->a_type == USER_OBJ ||
2199 ace->a_type == GROUP_OBJ ||
2200 ace->a_type == OTHER_OBJ ||
2201 ace->a_type == CLASS_OBJ))
2206 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
2208 static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
2211 #ifdef HAVE_EXTENDED_ACL
2217 * See if this attribute has an ACL
2219 if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
2220 pathconf(attrname, _PC_ACL_ENABLED) > 0) {
2222 * See if there is a non trivial acl on the file.
2224 if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
2225 acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
2228 return bxattr_exit_ok;
2230 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2231 attrname, jcr->last_fname, be.bstrerror());
2232 Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
2233 attrname, jcr->last_fname, be.bstrerror());
2234 return bxattr_exit_error;
2239 #if defined(ACL_SID_FMT)
2241 * New format flag added in newer Solaris versions.
2243 flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
2245 flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
2246 #endif /* ACL_SID_FMT */
2248 *acl_text = acl_totext(aclp, flags);
2256 return bxattr_exit_ok;
2257 #else /* HAVE_EXTENDED_ACL */
2259 aclent_t *acls = NULL;
2263 * See if this attribute has an ACL
2266 n = facl(fd, GETACLCNT, 0, NULL);
2268 n = acl(attrname, GETACLCNT, 0, NULL);
2271 if (n >= MIN_ACL_ENTRIES) {
2272 acls = (aclent_t *)malloc(n * sizeof(aclent_t));
2273 if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
2274 acl(attrname, GETACL, n, acls) != n) {
2278 return bxattr_exit_ok;
2280 Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
2281 attrname, jcr->last_fname, be.bstrerror());
2282 Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
2283 attrname, jcr->last_fname, be.bstrerror());
2285 return bxattr_exit_error;
2290 * See if there is a non trivial acl on the file.
2292 if (!acl_is_trivial(n, acls)) {
2293 if ((*acl_text = acltotext(acls, n)) == NULL) {
2294 Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
2295 attrname, jcr->last_fname, be.bstrerror());
2296 Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
2297 attrname, jcr->last_fname, be.bstrerror());
2299 return bxattr_exit_error;
2309 return bxattr_exit_ok;
2310 #endif /* HAVE_EXTENDED_ACL */
2312 #else /* HAVE_ACL */
2313 return bxattr_exit_ok;
2314 #endif /* HAVE_ACL */
2318 * Forward declaration for recursive function call.
2320 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
2323 * Save an extended or extensible attribute.
2324 * This is stored as an opaque stream of bytes with the following encoding:
2326 * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_data>
2328 * or for a hardlinked or symlinked attribute
2330 * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
2332 * xattr_name can be a subpath relative to the file the xattr is on.
2333 * stat_buffer is the string representation of the stat struct.
2334 * acl_string is an acl text when a non trivial acl is set on the xattr.
2335 * actual_xattr_data is the content of the xattr file.
2337 static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
2338 const char *attrname, bool toplevel_hidden_dir, int stream)
2343 xattr_link_cache_entry_t *xlce;
2344 char target_attrname[PATH_MAX];
2345 char link_source[PATH_MAX];
2346 char *acl_text = NULL;
2347 char attribs[MAXSTRING];
2348 char buffer[XATTR_BUFSIZ];
2349 bxattr_exit_code retval = bxattr_exit_error;
2352 bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
2355 * Get the stats of the extended or extensible attribute.
2357 if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
2360 retval = bxattr_exit_ok;
2363 Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
2364 target_attrname, jcr->last_fname, be.bstrerror());
2365 Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
2366 target_attrname, jcr->last_fname, be.bstrerror());
2372 * Based on the filetype perform the correct action. We support most filetypes here, more
2373 * then the actual implementation on Solaris supports so some code may never get executed
2374 * due to limitations in the implementation.
2376 switch (st.st_mode & S_IFMT) {
2381 * Get any acl on the xattr.
2383 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2387 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2388 * Encode the stat struct into an ASCII representation.
2390 encode_stat(attribs, &st, 0, stream);
2391 cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
2392 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2396 * Get any acl on the xattr.
2398 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
2402 * See if this is the toplevel_hidden_dir being saved.
2404 if (toplevel_hidden_dir) {
2406 * Save the data for later storage when we encounter a real xattr. We store the data
2407 * in the jcr->xattr_data->content buffer and flush that just before sending out the
2408 * first real xattr. Encode the stat struct into an ASCII representation and jump
2409 * out of the function.
2411 encode_stat(attribs, &st, 0, stream);
2412 cnt = bsnprintf(buffer, sizeof(buffer),
2414 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2415 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2416 jcr->xattr_data->content_length = cnt;
2420 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2421 * Encode the stat struct into an ASCII representation.
2423 encode_stat(attribs, &st, 0, stream);
2424 cnt = bsnprintf(buffer, sizeof(buffer),
2426 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2431 * If this is a hardlinked file check the inode cache for a hit.
2433 if (st.st_nlink > 1) {
2435 * See if the cache already knows this inode number.
2437 if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
2439 * Generate a xattr encoding with the reference to the target in there.
2441 encode_stat(attribs, &st, st.st_ino, stream);
2442 cnt = bsnprintf(buffer, sizeof(buffer),
2444 target_attrname, 0, attribs, 0, xlce->target, 0);
2445 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2446 jcr->xattr_data->content_length = cnt;
2447 retval = send_xattr_stream(jcr, stream);
2450 * For a hard linked file we are ready now, no need to recursively save the attributes.
2456 * Store this hard linked file in the cache.
2457 * Store the name relative to the top level xattr space.
2459 add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
2463 * Get any acl on the xattr.
2465 if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
2470 * Encode the stat struct into an ASCII representation.
2472 encode_stat(attribs, &st, 0, stream);
2473 cnt = bsnprintf(buffer, sizeof(buffer),
2475 target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
2478 * Open the extended or extensible attribute file.
2480 if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
2483 retval = bxattr_exit_ok;
2486 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
2487 target_attrname, jcr->last_fname, be.bstrerror());
2488 Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
2489 target_attrname, jcr->last_fname, be.bstrerror());
2496 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2497 * Encode the stat struct into an ASCII representation.
2499 if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
2502 retval = bxattr_exit_ok;
2505 Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
2506 target_attrname, jcr->last_fname, be.bstrerror());
2507 Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
2508 target_attrname, jcr->last_fname, be.bstrerror());
2514 * Generate a xattr encoding with the reference to the target in there.
2516 encode_stat(attribs, &st, st.st_ino, stream);
2517 cnt = bsnprintf(buffer, sizeof(buffer),
2519 target_attrname, 0, attribs, 0, link_source, 0);
2520 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2521 jcr->xattr_data->content_length = cnt;
2522 retval = send_xattr_stream(jcr, stream);
2524 if (retval == bxattr_exit_ok) {
2525 jcr->xattr_data->nr_saved++;
2529 * For a soft linked file we are ready now, no need to recursively save the attributes.
2537 * See if this is the first real xattr being saved.
2538 * If it is save the toplevel_hidden_dir attributes first.
2539 * This is easy as its stored already in the jcr->xattr_data->content buffer.
2541 if (jcr->xattr_data->nr_saved == 0) {
2542 retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
2543 if (retval != bxattr_exit_ok) {
2546 jcr->xattr_data->nr_saved++;
2549 pm_memcpy(jcr->xattr_data->content, buffer, cnt);
2550 jcr->xattr_data->content_length = cnt;
2553 * Only dump the content of regular files.
2555 switch (st.st_mode & S_IFMT) {
2557 if (st.st_size > 0) {
2559 * Protect ourself against things getting out of hand.
2561 if (st.st_size >= MAX_XATTR_STREAM) {
2562 Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
2563 jcr->last_fname, MAX_XATTR_STREAM);
2567 while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
2568 jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
2569 memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
2570 jcr->xattr_data->content_length += cnt;
2574 Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
2575 target_attrname, jcr->last_fname);
2576 Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
2577 target_attrname, jcr->last_fname);
2588 retval = send_xattr_stream(jcr, stream);
2589 if (retval == bxattr_exit_ok) {
2590 jcr->xattr_data->nr_saved++;
2595 * Recursivly call solaris_save_extended_attributes for archiving the attributes
2596 * available on this extended attribute.
2599 retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
2602 * The recursive call could change our working dir so change back to the wanted workdir.
2604 if (fchdir(fd) < 0) {
2607 retval = bxattr_exit_ok;
2610 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
2611 jcr->last_fname, be.bstrerror());
2612 Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
2613 jcr->last_fname, fd, be.bstrerror());
2620 if (acl_text != NULL) {
2629 static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
2632 int fd, filefd = -1, attrdirfd = -1;
2635 char current_xattr_namespace[PATH_MAX];
2636 bxattr_exit_code retval = bxattr_exit_error;
2640 * Determine what argument to use. Use attr_parent when set
2641 * (recursive call) or jcr->last_fname for first call. Also save
2642 * the current depth of the xattr_space we are in.
2646 if (xattr_namespace) {
2647 bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
2648 xattr_namespace, attr_parent);
2650 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2653 name = jcr->last_fname;
2654 bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
2658 * Open the file on which to save the xattrs read-only.
2660 if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
2663 retval = bxattr_exit_ok;
2666 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2667 jcr->last_fname, be.bstrerror());
2668 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2669 jcr->last_fname, be.bstrerror());
2675 * Open the xattr naming space.
2677 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2681 * Gentile way of the system saying this type of xattr layering is not supported.
2682 * Which is not problem we just forget about this this xattr.
2683 * But as this is not an error we return a positive return value.
2685 retval = bxattr_exit_ok;
2688 retval = bxattr_exit_ok;
2691 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2692 name, jcr->last_fname, be.bstrerror());
2693 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2694 name, jcr->last_fname, be.bstrerror());
2700 * We need to change into the attribute directory to determine if each of the
2701 * attributes should be saved.
2703 if (fchdir(attrdirfd) < 0) {
2704 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2705 jcr->last_fname, be.bstrerror());
2706 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2707 jcr->last_fname, attrdirfd, be.bstrerror());
2712 * Save the data of the toplevel xattr hidden_dir. We save this one before anything
2713 * else because the readdir returns "." entry after the extensible attr entry.
2714 * And as we want this entry before anything else we better just save its data.
2717 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
2718 true, STREAM_XATTR_SOLARIS);
2720 if ((fd = dup(attrdirfd)) == -1 ||
2721 (dirp = fdopendir(fd)) == (DIR *)NULL) {
2722 Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
2723 jcr->last_fname, be.bstrerror());
2724 Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
2725 jcr->last_fname, fd, be.bstrerror());
2731 * Walk the namespace.
2733 while ((dp = readdir(dirp)) != NULL) {
2735 * Skip only the toplevel . dir.
2737 if (!attr_parent && bstrcmp(dp->d_name, "."))
2741 * Skip all .. directories
2743 if (bstrcmp(dp->d_name, ".."))
2746 Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
2747 current_xattr_namespace, dp->d_name, jcr->last_fname);
2749 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
2751 * We are not interested in read-only extensible attributes.
2753 if (bstrcmp(dp->d_name, VIEW_READONLY)) {
2754 Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
2755 current_xattr_namespace, dp->d_name, jcr->last_fname);
2761 * We are only interested in read-write extensible attributes
2762 * when they contain non-transient values.
2764 if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
2766 * Determine if there are non-transient system attributes at the toplevel.
2767 * We need to provide a fd to the open file.
2769 if (!solaris_has_non_transient_extensible_attributes(filefd)) {
2770 Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
2771 current_xattr_namespace, dp->d_name, jcr->last_fname);
2778 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2779 false, STREAM_XATTR_SOLARIS_SYS);
2782 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
2787 solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
2788 false, STREAM_XATTR_SOLARIS);
2792 retval = bxattr_exit_ok;
2795 if (attrdirfd != -1)
2803 static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
2805 #ifdef HAVE_EXTENDED_ACL
2810 if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
2811 Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
2813 return bxattr_exit_error;
2816 if ((fd != -1 && facl_set(fd, aclp) != 0) ||
2817 acl_set(attrname, aclp) != 0) {
2818 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2819 attrname, jcr->last_fname, be.bstrerror());
2820 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2821 attrname, jcr->last_fname, be.bstrerror());
2822 return bxattr_exit_error;
2828 return bxattr_exit_ok;
2830 #else /* HAVE_EXTENDED_ACL */
2832 aclent_t *acls = NULL;
2835 acls = aclfromtext(acl_text, &n);
2837 if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
2838 acl(attrname, SETACL, n, acls) != 0) {
2839 Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
2840 attrname, jcr->last_fname, be.bstrerror());
2841 Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
2842 attrname, jcr->last_fname, be.bstrerror());
2843 return bxattr_exit_error;
2850 return bxattr_exit_ok;
2852 #endif /* HAVE_EXTENDED_ACL */
2855 #endif /* HAVE_ACL */
2857 static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
2859 int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
2860 int used_bytes, total_bytes, cnt;
2861 char *bp, *target_attrname, *attribs;
2862 char *linked_target = NULL;
2863 char *acl_text = NULL;
2867 struct timeval times[2];
2868 bxattr_exit_code retval = bxattr_exit_error;
2872 * Parse the xattr stream. First the part that is the same for all xattrs.
2875 total_bytes = jcr->xattr_data->content_length;
2878 * The name of the target xattr has a leading / we are not interested
2879 * in that so skip it when decoding the string. We always start a the /
2880 * of the xattr space anyway.
2882 target_attrname = jcr->xattr_data->content + 1;
2883 if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
2884 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2890 * Open the file on which to restore the xattrs read-only.
2892 if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
2893 Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
2894 jcr->last_fname, be.bstrerror());
2895 Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
2896 jcr->last_fname, be.bstrerror());
2901 * Open the xattr naming space and make it the current working dir.
2903 if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2904 Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
2905 jcr->last_fname, be.bstrerror());
2906 Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
2907 jcr->last_fname, be.bstrerror());
2911 if (fchdir(attrdirfd) < 0) {
2912 Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
2913 jcr->last_fname, be.bstrerror());
2914 Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
2915 jcr->last_fname, attrdirfd, be.bstrerror());
2920 * Try to open the correct xattr subdir based on the target_attrname given.
2921 * e.g. check if its a subdir attrname. Each / in the string makes us go
2924 while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
2927 if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
2928 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
2929 target_attrname, jcr->last_fname, be.bstrerror());
2930 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
2931 target_attrname, jcr->last_fname, be.bstrerror());
2939 * Open the xattr naming space.
2941 if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
2942 Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
2943 target_attrname, jcr->last_fname, be.bstrerror());
2944 Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
2945 target_attrname, jcr->last_fname, be.bstrerror());
2953 * Make the xattr space our current workingdir.
2955 if (fchdir(attrdirfd) < 0) {
2956 Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
2957 target_attrname, jcr->last_fname, be.bstrerror());
2958 Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
2959 target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
2963 target_attrname = ++bp;
2967 * Decode the attributes from the stream.
2969 decode_stat(attribs, &st, &inum);
2972 * Decode the next field (acl_text).
2974 if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
2975 (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
2981 * Based on the filetype perform the correct action. We support most filetypes here, more
2982 * then the actual implementation on Solaris supports so some code may never get executed
2983 * due to limitations in the implementation.
2985 switch (st.st_mode & S_IFMT) {
2988 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
2990 unlinkat(attrdirfd, target_attrname, 0);
2991 if (mkfifo(target_attrname, st.st_mode) < 0) {
2992 Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
2993 target_attrname, jcr->last_fname, be.bstrerror());
2994 Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
2995 target_attrname, jcr->last_fname, be.bstrerror());
3002 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3004 unlinkat(attrdirfd, target_attrname, 0);
3005 if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
3006 Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
3007 target_attrname, jcr->last_fname, be.bstrerror());
3008 Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
3009 target_attrname, jcr->last_fname, be.bstrerror());
3015 * If its not the hidden_dir create the entry.
3016 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3018 if (!bstrcmp(target_attrname, ".")) {
3019 unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
3020 if (mkdir(target_attrname, st.st_mode) < 0) {
3021 Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
3022 target_attrname, jcr->last_fname, be.bstrerror());
3023 Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
3024 target_attrname, jcr->last_fname, be.bstrerror());
3031 * See if this is a hard linked file. e.g. inum != 0
3036 unlinkat(attrdirfd, target_attrname, 0);
3037 if (link(linked_target, target_attrname) < 0) {
3038 Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
3039 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3040 Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
3041 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3046 * Successfully restored xattr.
3048 retval = bxattr_exit_ok;
3051 if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
3052 (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
3056 if (used_bytes < (total_bytes - 1))
3060 * Restore the actual xattr.
3062 if (!is_extensible) {
3063 unlinkat(attrdirfd, target_attrname, 0);
3066 if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
3067 Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
3068 target_attrname, jcr->last_fname, be.bstrerror());
3069 Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
3070 target_attrname, jcr->last_fname, be.bstrerror());
3076 * Restore the actual data.
3078 if (st.st_size > 0) {
3079 used_bytes = (data - jcr->xattr_data->content);
3080 cnt = total_bytes - used_bytes;
3083 * Do a sanity check, the st.st_size should be the same as the number of bytes
3084 * we have available as data of the stream.
3086 if (cnt != st.st_size) {
3087 Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
3088 target_attrname, jcr->last_fname);
3089 Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
3090 target_attrname, jcr->last_fname);
3095 cnt = write(attrfd, data, cnt);
3097 Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
3098 target_attrname, jcr->last_fname, be.bstrerror());
3099 Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
3100 target_attrname, jcr->last_fname, be.bstrerror());
3106 cnt = total_bytes - used_bytes;
3112 * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
3116 if (symlink(linked_target, target_attrname) < 0) {
3117 Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
3118 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3119 Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
3120 target_attrname, linked_target, jcr->last_fname, be.bstrerror());
3125 * Successfully restored xattr.
3127 retval = bxattr_exit_ok;
3134 * Restore owner and acl for non extensible attributes.
3136 if (!is_extensible) {
3137 if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
3141 * Gentile way of the system saying this type of xattr layering is not supported.
3142 * But as this is not an error we return a positive return value.
3144 retval = bxattr_exit_ok;
3147 retval = bxattr_exit_ok;
3150 Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
3151 target_attrname, jcr->last_fname, be.bstrerror());
3152 Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
3153 target_attrname, jcr->last_fname, be.bstrerror());
3160 if (acl_text && *acl_text)
3161 if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
3163 #endif /* HAVE_ACL */
3166 * For a non extensible attribute restore access and modification time on the xattr.
3168 if (!is_extensible) {
3169 times[0].tv_sec = st.st_atime;
3170 times[0].tv_usec = 0;
3171 times[1].tv_sec = st.st_mtime;
3172 times[1].tv_usec = 0;
3174 if (futimesat(attrdirfd, target_attrname, times) < 0) {
3175 Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
3176 target_attrname, jcr->last_fname, be.bstrerror());
3177 Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
3178 target_attrname, jcr->last_fname, be.bstrerror());
3184 * Successfully restored xattr.
3186 retval = bxattr_exit_ok;
3190 Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
3192 Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
3199 if (attrdirfd != -1) {
3208 static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3211 bxattr_exit_code retval = bxattr_exit_ok;
3214 * First see if extended attributes or extensible attributes are present.
3215 * If not just pretend things went ok.
3217 if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
3218 jcr->xattr_data->nr_saved = 0;
3219 jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
3222 * As we change the cwd in the save function save the current cwd
3223 * for restore after return from the solaris_save_xattrs function.
3225 getcwd(cwd, sizeof(cwd));
3226 retval = solaris_save_xattrs(jcr, NULL, NULL);
3228 delete jcr->xattr_data->link_cache;
3229 jcr->xattr_data->link_cache = NULL;
3234 static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
3237 bool is_extensible = false;
3238 bxattr_exit_code retval;
3241 * First make sure we can restore xattr on the filesystem.
3244 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
3245 case STREAM_XATTR_SOLARIS_SYS:
3246 if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
3247 Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
3248 Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
3250 return bxattr_exit_error;
3253 is_extensible = true;
3256 case STREAM_XATTR_SOLARIS:
3257 if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
3258 Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
3259 Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
3261 return bxattr_exit_error;
3265 return bxattr_exit_error;
3269 * As we change the cwd in the restore function save the current cwd
3270 * for restore after return from the solaris_restore_xattrs function.
3272 getcwd(cwd, sizeof(cwd));
3273 retval = solaris_restore_xattrs(jcr, is_extensible);
3280 * Function pointers to the build and parse function to use for these xattrs.
3282 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
3283 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
3285 #endif /* defined(HAVE_SUN_OS) */
3288 * Entry points when compiled with support for XATTRs on a supported platform.
3290 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
3292 if (os_build_xattr_streams) {
3293 return (*os_build_xattr_streams)(jcr, ff_pkt);
3295 return bxattr_exit_error;
3298 bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
3302 if (os_parse_xattr_streams) {
3304 * See if we can parse this stream, and ifso give it a try.
3306 for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
3307 if (os_default_xattr_streams[cnt] == stream) {
3308 return (*os_parse_xattr_streams)(jcr, stream);
3313 * Issue a warning and discard the message. But pretend the restore was ok.
3315 Jmsg2(jcr, M_WARNING, 0,
3316 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
3317 jcr->last_fname, stream);
3318 return bxattr_exit_error;