2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2008 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:
40 * Written by Marco van Wieringen, November MMVIII
42 * Version $Id: xattr.c 7879 2008-10-23 10:12:36Z kerns $
49 /* Klude to fix Darwin build -- KES */
56 * List of supported OSs.
58 #if !defined(HAVE_XATTR) /* Extended Attributes support is required, of course */ \
59 || !( defined(HAVE_DARWIN_OS) \
60 || defined(HAVE_FREEBSD_OS) \
61 || defined(HAVE_LINUX_OS) \
62 || defined(HAVE_NETBSD_OS) \
65 bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
67 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
71 bool parse_xattr_stream(JCR *jcr, int stream)
73 Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n"));
79 #ifdef HAVE_SYS_XATTR_H
80 #include <sys/xattr.h>
83 #if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)
84 #define lgetxattr getxattr
86 #if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR)
87 #define lsetxattr setxattr
89 #if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)
90 #define llistxattr listxattr
94 * Send a XATTR stream to the SD.
96 static bool send_xattr_stream(JCR *jcr, int stream, int len)
98 BSOCK *sd = jcr->store_bsock;
100 #ifdef FD_NO_SEND_TEST
107 if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
108 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
115 * Send the buffer to the storage deamon
117 Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data);
119 sd->msg = jcr->xattr_data;
124 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
130 jcr->JobBytes += sd->msglen;
132 if (!sd->signal(BNET_EOD)) {
133 Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
139 Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
144 static void xattr_drop_internal_table(xattr_t *xattr_value_list)
146 xattr_t *current_xattr;
149 * Walk the list of xattrs and free allocated memory on traversing.
151 for (current_xattr = xattr_value_list;
152 current_xattr != (xattr_t *)NULL;
155 * See if we can shortcut.
157 if (current_xattr->magic != XATTR_MAGIC)
160 free(current_xattr->name);
162 if (current_xattr->value_length > 0)
163 free(current_xattr->value);
167 * Free the array of control structs.
169 free(xattr_value_list);
173 static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list)
175 xattr_t *current_xattr;
179 * Make sure the serialized stream fits in the poolmem buffer.
180 * We allocate some more to be sure the stream is gonna fit.
182 jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, expected_serialize_len + 10);
183 ser_begin(jcr->xattr_data, expected_serialize_len + 10);
186 * Walk the list of xattrs and serialize the data.
188 for (current_xattr = xattr_value_list; current_xattr != (xattr_t *)NULL; current_xattr++) {
190 * See if we can shortcut.
192 if (current_xattr->magic != XATTR_MAGIC)
195 ser_uint32(current_xattr->magic);
196 ser_uint32(current_xattr->name_length);
197 ser_bytes(current_xattr->name, current_xattr->name_length);
199 ser_uint32(current_xattr->value_length);
200 ser_bytes(current_xattr->value, current_xattr->value_length);
203 ser_end(jcr->xattr_data, expected_serialize_len + 10);
205 return ser_length(jcr->xattr_data);
208 static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
211 int32_t xattr_list_len,
213 expected_serialize_len = 0,
215 char *xattr_list, *bp;
216 xattr_t *xattr_value_list, *current_xattr;
219 * First get the length of the available list with extended attributes.
221 xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
222 if (xattr_list_len < 0) {
224 Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
225 jcr->last_fname, be.bstrerror());
226 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
227 jcr->last_fname, be.bstrerror());
229 } else if (xattr_list_len == 0) {
234 * Allocate room for the extented attribute list.
236 if ((xattr_list = (char *)malloc(xattr_list_len + 1)) == (char *)NULL) {
237 Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), xattr_list_len + 1);
241 memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
244 * Get the actual list of extended attributes names for a file.
246 xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
247 if (xattr_list_len < 0) {
249 Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
250 jcr->last_fname, be.bstrerror());
251 Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
252 jcr->last_fname, be.bstrerror());
257 xattr_list[xattr_list_len] = '\0';
260 * Count the number of extended attributes on a file.
263 while ((bp - xattr_list) + 1 < xattr_list_len) {
266 bp = strchr(bp, '\0') + 1;
270 * Allocate enough room to hold all extended attributes.
271 * After allocating the storage make sure its empty by zeroing it.
273 if ((xattr_value_list = (xattr_t *)malloc(count * sizeof(xattr_t))) == (xattr_t *)NULL) {
274 Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), count * sizeof(xattr_t));
278 memset((caddr_t)xattr_value_list, 0, count * sizeof(xattr_t));
281 * Walk the list of extended attributes names and retrieve the data.
282 * We already count the bytes needed for serializing the stream later on.
284 current_xattr = xattr_value_list;
286 while ((bp - xattr_list) + 1 < xattr_list_len) {
287 #if defined(HAVE_LINUX_OS)
289 * On Linux you also get the acls in the extented attribute list.
290 * So we check if we are already backing up acls and if we do we
291 * don't store the extended attribute with the same info.
293 if (ff_pkt->flags & FO_ACL && !strcmp(bp, "system.posix_acl_access")) {
294 bp = strchr(bp, '\0') + 1;
301 * Each xattr valuepair starts with a magic so we can parse it easier.
303 current_xattr->magic = XATTR_MAGIC;
304 expected_serialize_len += sizeof(current_xattr->magic);
307 * Allocate space for storing the name.
309 current_xattr->name_length = strlen(bp);
310 if ((current_xattr->name = (char *)malloc(current_xattr->name_length)) == (char *)NULL) {
311 Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), current_xattr->name_length);
315 memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
317 expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
320 * First see how long the value is for the extended attribute.
322 xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
323 if (xattr_value_len < 0) {
325 Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
326 jcr->last_fname, be.bstrerror());
327 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
328 jcr->last_fname, be.bstrerror());
334 * Allocate space for storing the value.
336 if ((current_xattr->value = (char *)malloc(xattr_value_len)) == (char *)NULL) {
337 Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), xattr_value_len);
341 memset((caddr_t)current_xattr->value, 0, xattr_value_len);
343 xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
344 if (xattr_value_len < 0) {
346 Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
347 jcr->last_fname, be.bstrerror());
348 Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
349 jcr->last_fname, be.bstrerror());
355 * Store the actual length of the value.
357 current_xattr->value_length = xattr_value_len;
359 expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
365 bp = strchr(bp, '\0') + 1;
369 * Serialize the datastream.
371 if ((serialize_len = serialize_xattr_stream(jcr, expected_serialize_len,
372 xattr_value_list)) < expected_serialize_len) {
373 Jmsg1(jcr, M_ERROR, 0, _("failed to serialize extended attributes on file \"%s\"\n"),
379 xattr_drop_internal_table(xattr_value_list);
383 * Send the datastream to the SD.
385 return send_xattr_stream(jcr, stream, serialize_len);
388 xattr_drop_internal_table(xattr_value_list);
394 static bool generic_xattr_parse_streams(JCR *jcr)
397 xattr_t current_xattr;
401 * Parse the stream and perform the setxattr calls on the file.
403 * Start unserializing the data. We keep on looping while we have not
404 * unserialized all bytes in the stream.
406 unser_begin(jcr->xattr_data, jcr->xattr_data_len);
407 while (unser_length(jcr->xattr_data) < jcr->xattr_data_len) {
409 * First make sure the magic is present. This way we can easily catch corruption.
410 * Any missing MAGIC is fatal we do NOT try to continue.
412 unser_uint32(current_xattr.magic);
413 if (current_xattr.magic != XATTR_MAGIC) {
414 Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
421 * Decode the valuepair. First decode the length of the name.
423 unser_uint32(current_xattr.name_length);
426 * Allocate room for the name and decode its content.
428 if ((current_xattr.name = (char *)malloc(current_xattr.name_length + 1)) == (char *)NULL) {
429 Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), current_xattr.name_length + 1);
433 unser_bytes(current_xattr.name, current_xattr.name_length);
436 * The xattr_name needs to be null terminated for lsetxattr.
438 current_xattr.name[current_xattr.name_length] = '\0';
441 * Decode the value length.
443 unser_uint32(current_xattr.value_length);
446 * Allocate room for the value and decode its content.
448 if ((current_xattr.value = (char *)malloc(current_xattr.value_length)) == (char *)NULL) {
449 Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), current_xattr.value_length);
453 unser_bytes(current_xattr.value, current_xattr.value_length);
456 * Try to set the extended attribute on the file.
457 * If we fail to set this attribute we flag the error but its not fatal,
458 * we try to restore the other extended attributes too.
460 if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
461 current_xattr.value_length, 0) != 0) {
463 Jmsg2(jcr, M_ERROR, 0, _("lsetxattr error on file \"%s\": ERR=%s\n"),
464 jcr->last_fname, be.bstrerror());
465 Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
466 jcr->last_fname, be.bstrerror());
469 * Reset the return flag to false to indicate one or more extended attributes
470 * could not be restored.
476 * Free the temporary buffers.
478 free(current_xattr.name);
479 free(current_xattr.value);
482 unser_end(jcr->xattr_data, jcr->xattr_data_len);
486 #if defined(HAVE_DARWIN_OS)
487 static bool darwin_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
489 return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_DARWIN);
492 static bool darwin_parse_xattr_stream(JCR *jcr, int stream)
495 case STREAM_XATTR_DARWIN:
496 return generic_xattr_parse_streams(jcr);
499 #elif defined(HAVE_FREEBSD_OS)
500 static bool freebsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
502 return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_FREEBSD);
505 static bool freebsd_parse_xattr_stream(JCR *jcr, int stream)
508 case STREAM_XATTR_FREEBSD:
509 return generic_xattr_parse_streams(jcr);
512 #elif defined(HAVE_LINUX_OS)
513 static bool linux_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
515 return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_LINUX);
518 static bool linux_parse_xattr_stream(JCR *jcr, int stream)
521 case STREAM_XATTR_LINUX:
522 return generic_xattr_parse_streams(jcr);
526 #elif defined(HAVE_NETBSD_OS)
527 static bool netbsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
529 return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_NETBSD);
532 static bool netbsd_parse_xattr_stream(JCR *jcr, int stream)
535 case STREAM_XATTR_NETBSD:
536 return generic_xattr_parse_streams(jcr);
542 bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
544 #if defined(HAVE_DARWIN_OS)
545 return darwin_build_xattr_streams(jcr, ff_pkt);
546 #elif defined(HAVE_FREEBSD_OS)
547 return freebsd_build_xattr_streams(jcr, ff_pkt);
548 #elif defined(HAVE_LINUX_OS)
549 return linux_build_xattr_streams(jcr, ff_pkt);
550 #elif defined(HAVE_NETBSD_OS)
551 return netbsd_build_xattr_streams(jcr, ff_pkt);
555 bool parse_xattr_stream(JCR *jcr, int stream)
558 * Based on the stream being passed in dispatch to the right function
559 * for parsing and restoring a specific xattr. The platform determines
560 * which streams are recognized and parsed and which are handled by
561 * the default case and ignored. As only one of the platform defines
562 * is true per compile we never end up with duplicate switch values.
565 #if defined(HAVE_DARWIN_OS)
566 case STREAM_XATTR_DARWIN:
567 return darwin_parse_xattr_stream(jcr, stream);
568 #elif defined(HAVE_FREEBSD_OS)
569 case STREAM_XATTR_FREEBSD:
570 return freebsd_parse_xattr_stream(jcr, stream);
571 #elif defined(HAVE_LINUX_OS)
572 case STREAM_XATTR_LINUX:
573 return linux_parse_xattr_stream(jcr, stream);
574 #elif defined(HAVE_NETBSD_OS)
575 case STREAM_XATTR_NETBSD:
576 return netbsd_parse_xattr_stream(jcr, stream);
580 * Issue a warning and discard the message. But pretend the restore was ok.
582 Qmsg2(jcr, M_WARNING, 0,
583 _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
584 jcr->last_fname, stream);
586 } /* end switch (stream) */