From: Kern Sibbald Date: Wed, 26 Nov 2008 14:11:19 +0000 (+0000) Subject: Add missing files for xattr and eliminate a few compiler complaints X-Git-Tag: Release-7.0.0~3695 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=1cecc827f986ce8c594f5f368d75d9a0abc5b3d8;p=bacula%2Fbacula Add missing files for xattr and eliminate a few compiler complaints git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@8087 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/src/filed/protos.h b/bacula/src/filed/protos.h index 8c3dcb77fe..428a9ddf7c 100644 --- a/bacula/src/filed/protos.h +++ b/bacula/src/filed/protos.h @@ -1,10 +1,7 @@ -/* - * Version $Id$ - */ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2006 Free Software Foundation Europe e.V. + Copyright (C) 2000-2008 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. @@ -28,6 +25,9 @@ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. */ +/* + * Version $Id$ + */ extern bool blast_data_to_storage_daemon(JCR *jcr, char *addr); extern void do_verify_volume(JCR *jcr); @@ -62,4 +62,3 @@ void unstrip_path(FF_PKT *ff_pkt); /* from xattr.c */ bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt); bool parse_xattr_stream(JCR *jcr, int stream); - diff --git a/bacula/src/filed/xattr.c b/bacula/src/filed/xattr.c new file mode 100644 index 0000000000..acbf968d1b --- /dev/null +++ b/bacula/src/filed/xattr.c @@ -0,0 +1,583 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Functions to handle Extended Attributes for bacula. + * + * Extended Attributes are so OS specific we only restore Extended Attributes if + * they were saved using a filed on the same platform. + * + * Currently we support the following OSes: + * - FreeBSD + * - Darwin + * - Linux + * - NetBSD + * + * Written by Marco van Wieringen, November MMVIII + * + * Version $Id: xattr.c 7879 2008-10-23 10:12:36Z kerns $ + */ + +#include "bacula.h" +#include "filed.h" +#include "xattr.h" + +/* + * List of supported OSs. + */ +#if !defined(HAVE_XATTR) /* Extended Attributes support is required, of course */ \ + || !( defined(HAVE_DARWIN_OS) \ + || defined(HAVE_FREEBSD_OS) \ + || defined(HAVE_LINUX_OS) \ + || defined(HAVE_NETBSD_OS) \ + ) + +bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt) +{ + Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n")); + return false; +} + +bool parse_xattr_stream(JCR *jcr, int stream) +{ + Jmsg(jcr, M_FATAL, 0, _("XATTR support not configured for your machine.\n")); + return false; +} + +#else + +#ifdef HAVE_SYS_XATTR_H +#include +#endif + +#if defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR) +#define lgetxattr getxattr +#endif +#if defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR) +#define lsetxattr setxattr +#endif +#if defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR) +#define llistxattr listxattr +#endif + +/* + * Send a XATTR stream to the SD. + */ +static bool send_xattr_stream(JCR *jcr, int stream, int len) +{ + BSOCK *sd = jcr->store_bsock; + POOLMEM *msgsave; +#ifdef FD_NO_SEND_TEST + return true; +#endif + + /* + * Send header + */ + if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) { + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + sd->bstrerror()); + + return false; + } + + /* + * Send the buffer to the storage deamon + */ + Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data); + msgsave = sd->msg; + sd->msg = jcr->xattr_data; + sd->msglen = len; + if (!sd->send()) { + sd->msg = msgsave; + sd->msglen = 0; + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + sd->bstrerror()); + + return false; + } + + jcr->JobBytes += sd->msglen; + sd->msg = msgsave; + if (!sd->signal(BNET_EOD)) { + Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), + sd->bstrerror()); + + return false; + } + + Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname); + + return true; +} + +static void xattr_drop_internal_table(xattr_t *xattr_value_list) +{ + xattr_t *current_xattr; + + /* + * Walk the list of xattrs and free allocated memory on traversing. + */ + for (current_xattr = xattr_value_list; + current_xattr != (xattr_t *)NULL; + current_xattr++) { + /* + * See if we can shortcut. + */ + if (current_xattr->magic != XATTR_MAGIC) + break; + + free(current_xattr->name); + + if (current_xattr->value_length > 0) + free(current_xattr->value); + } + + /* + * Free the array of control structs. + */ + free(xattr_value_list); +} + + +static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len, xattr_t *xattr_value_list) +{ + xattr_t *current_xattr; + ser_declare; + + /* + * Make sure the serialized stream fits in the poolmem buffer. + * We allocate some more to be sure the stream is gonna fit. + */ + jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, expected_serialize_len + 10); + ser_begin(jcr->xattr_data, expected_serialize_len + 10); + + /* + * Walk the list of xattrs and serialize the data. + */ + for (current_xattr = xattr_value_list; current_xattr != (xattr_t *)NULL; current_xattr++) { + /* + * See if we can shortcut. + */ + if (current_xattr->magic != XATTR_MAGIC) + break; + + ser_uint32(current_xattr->magic); + ser_uint32(current_xattr->name_length); + ser_bytes(current_xattr->name, current_xattr->name_length); + + ser_uint32(current_xattr->value_length); + ser_bytes(current_xattr->value, current_xattr->value_length); + } + + ser_end(jcr->xattr_data, expected_serialize_len + 10); + + return ser_length(jcr->xattr_data); +} + +static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream) +{ + int count = 0; + ssize_t xattr_list_len, + xattr_value_len, + expected_serialize_len = 0, + serialize_len = 0; + char *xattr_list, *bp; + xattr_t *xattr_value_list, *current_xattr; + + /* + * First get the length of the available list with extended attributes. + */ + xattr_list_len = llistxattr(jcr->last_fname, NULL, 0); + if (xattr_list_len < 0) { + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"), + jcr->last_fname, be.bstrerror()); + Dmsg2(100, "llistxattr error file=%s ERR=%s\n", + jcr->last_fname, be.bstrerror()); + return false; + } else if (xattr_list_len == 0) { + return true; + } + + /* + * Allocate room for the extented attribute list. + */ + if ((xattr_list = (char *)malloc(xattr_list_len + 1)) == (char *)NULL) { + Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), xattr_list_len + 1); + + return false; + } + memset((caddr_t)xattr_list, 0, xattr_list_len + 1); + + /* + * Get the actual list of extended attributes names for a file. + */ + xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len); + if (xattr_list_len < 0) { + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"), + jcr->last_fname, be.bstrerror()); + Dmsg2(100, "llistxattr error file=%s ERR=%s\n", + jcr->last_fname, be.bstrerror()); + + free(xattr_list); + return false; + } + xattr_list[xattr_list_len] = '\0'; + + /* + * Count the number of extended attributes on a file. + */ + bp = xattr_list; + while ((bp - xattr_list) + 1 < xattr_list_len) { + count++; + + bp = strchr(bp, '\0') + 1; + } + + /* + * Allocate enough room to hold all extended attributes. + * After allocating the storage make sure its empty by zeroing it. + */ + if ((xattr_value_list = (xattr_t *)malloc(count * sizeof(xattr_t))) == (xattr_t *)NULL) { + Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), count * sizeof(xattr_t)); + + return false; + } + memset((caddr_t)xattr_value_list, 0, count * sizeof(xattr_t)); + + /* + * Walk the list of extended attributes names and retrieve the data. + * We already count the bytes needed for serializing the stream later on. + */ + current_xattr = xattr_value_list; + bp = xattr_list; + while ((bp - xattr_list) + 1 < xattr_list_len) { +#if defined(HAVE_LINUX_OS) + /* + * On Linux you also get the acls in the extented attribute list. + * So we check if we are already backing up acls and if we do we + * don't store the extended attribute with the same info. + */ + if (ff_pkt->flags & FO_ACL && !strcmp(bp, "system.posix_acl_access")) { + bp = strchr(bp, '\0') + 1; + + continue; + } +#endif + + /* + * Each xattr valuepair starts with a magic so we can parse it easier. + */ + current_xattr->magic = XATTR_MAGIC; + expected_serialize_len += sizeof(current_xattr->magic); + + /* + * Allocate space for storing the name. + */ + current_xattr->name_length = strlen(bp); + if ((current_xattr->name = (char *)malloc(current_xattr->name_length)) == (char *)NULL) { + Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), current_xattr->name_length); + + goto bail_out; + } + memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length); + + expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length; + + /* + * First see how long the value is for the extended attribute. + */ + xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0); + if (xattr_value_len < 0) { + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"), + jcr->last_fname, be.bstrerror()); + Dmsg2(100, "lgetxattr error file=%s ERR=%s\n", + jcr->last_fname, be.bstrerror()); + + goto bail_out; + } + + /* + * Allocate space for storing the value. + */ + if ((current_xattr->value = (char *)malloc(xattr_value_len)) == (char *)NULL) { + Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), xattr_value_len); + + goto bail_out; + } + memset((caddr_t)current_xattr->value, 0, xattr_value_len); + + xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len); + if (xattr_value_len < 0) { + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"), + jcr->last_fname, be.bstrerror()); + Dmsg2(100, "lgetxattr error file=%s ERR=%s\n", + jcr->last_fname, be.bstrerror()); + + goto bail_out; + } + + /* + * Store the actual length of the value. + */ + current_xattr->value_length = xattr_value_len; + + expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length; + + /* + * Next attribute. + */ + current_xattr++; + bp = strchr(bp, '\0') + 1; + } + + /* + * Serialize the datastream. + */ + if ((serialize_len = serialize_xattr_stream(jcr, expected_serialize_len, + xattr_value_list)) < expected_serialize_len) { + Jmsg1(jcr, M_ERROR, 0, _("failed to serialize extended attributes on file \"%s\"\n"), + jcr->last_fname); + + goto bail_out; + } + + xattr_drop_internal_table(xattr_value_list); + free(xattr_list); + + /* + * Send the datastream to the SD. + */ + return send_xattr_stream(jcr, stream, serialize_len); + +bail_out: + xattr_drop_internal_table(xattr_value_list); + free(xattr_list); + + return false; +} + +static bool generic_xattr_parse_streams(JCR *jcr) +{ + unser_declare; + xattr_t current_xattr; + bool retval = true; + + /* + * Parse the stream and perform the setxattr calls on the file. + * + * Start unserializing the data. We keep on looping while we have not + * unserialized all bytes in the stream. + */ + unser_begin(jcr->xattr_data, jcr->xattr_data_len); + while (unser_length(jcr->xattr_data) < jcr->xattr_data_len) { + /* + * First make sure the magic is present. This way we can easily catch corruption. + * Any missing MAGIC is fatal we do NOT try to continue. + */ + unser_uint32(current_xattr.magic); + if (current_xattr.magic != XATTR_MAGIC) { + Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"), + jcr->last_fname); + + return false; + } + + /* + * Decode the valuepair. First decode the length of the name. + */ + unser_uint32(current_xattr.name_length); + + /* + * Allocate room for the name and decode its content. + */ + if ((current_xattr.name = (char *)malloc(current_xattr.name_length + 1)) == (char *)NULL) { + Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), current_xattr.name_length + 1); + + return false; + } + unser_bytes(current_xattr.name, current_xattr.name_length); + + /* + * The xattr_name needs to be null terminated for lsetxattr. + */ + current_xattr.name[current_xattr.name_length] = '\0'; + + /* + * Decode the value length. + */ + unser_uint32(current_xattr.value_length); + + /* + * Allocate room for the value and decode its content. + */ + if ((current_xattr.value = (char *)malloc(current_xattr.value_length)) == (char *)NULL) { + Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), current_xattr.value_length); + + return false; + } + unser_bytes(current_xattr.value, current_xattr.value_length); + + /* + * Try to set the extended attribute on the file. + * If we fail to set this attribute we flag the error but its not fatal, + * we try to restore the other extended attributes too. + */ + if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value, + current_xattr.value_length, 0) != 0) { + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("lsetxattr error on file \"%s\": ERR=%s\n"), + jcr->last_fname, be.bstrerror()); + Dmsg2(100, "lsetxattr error file=%s ERR=%s\n", + jcr->last_fname, be.bstrerror()); + + /* + * Reset the return flag to false to indicate one or more extended attributes + * could not be restored. + */ + retval = false; + } + + /* + * Free the temporary buffers. + */ + free(current_xattr.name); + free(current_xattr.value); + } + + unser_end(jcr->xattr_data, jcr->xattr_data_len); + return retval; +} + +#if defined(HAVE_DARWIN_OS) +static bool darwin_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt) +{ + return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_DARWIN); +} + +static bool darwin_parse_xattr_stream(JCR *jcr, int stream) +{ + switch (stream) { + case STREAM_XATTR_DARWIN: + return generic_xattr_parse_streams(jcr); + } +} +#elif defined(HAVE_FREEBSD_OS) +static bool freebsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt) +{ + return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_FREEBSD); +} + +static bool freebsd_parse_xattr_stream(JCR *jcr, int stream) +{ + switch (stream) { + case STREAM_XATTR_FREEBSD: + return generic_xattr_parse_streams(jcr); + } +} +#elif defined(HAVE_LINUX_OS) +static bool linux_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt) +{ + return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_LINUX); +} + +static bool linux_parse_xattr_stream(JCR *jcr, int stream) +{ + switch (stream) { + case STREAM_XATTR_LINUX: + return generic_xattr_parse_streams(jcr); + } + return false; +} +#elif defined(HAVE_NETBSD_OS) +static bool netbsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt) +{ + return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_NETBSD); +} + +static bool netbsd_parse_xattr_stream(JCR *jcr, int stream) +{ + switch (stream) { + case STREAM_XATTR_NETBSD: + return generic_xattr_parse_streams(jcr); + } + return false; +} +#endif + +bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt) +{ +#if defined(HAVE_DARWIN_OS) + return darwin_build_xattr_streams(jcr, ff_pkt); +#elif defined(HAVE_FREEBSD_OS) + return freebsd_build_xattr_streams(jcr, ff_pkt); +#elif defined(HAVE_LINUX_OS) + return linux_build_xattr_streams(jcr, ff_pkt); +#elif defined(HAVE_NETBSD_OS) + return netbsd_build_xattr_streams(jcr, ff_pkt); +#endif +} + +bool parse_xattr_stream(JCR *jcr, int stream) +{ + /* + * Based on the stream being passed in dispatch to the right function + * for parsing and restoring a specific xattr. The platform determines + * which streams are recognized and parsed and which are handled by + * the default case and ignored. As only one of the platform defines + * is true per compile we never end up with duplicate switch values. + */ + switch (stream) { +#if defined(HAVE_DARWIN_OS) + case STREAM_XATTR_DARWIN: + return darwin_parse_xattr_stream(jcr, stream); +#elif defined(HAVE_FREEBSD_OS) + case STREAM_XATTR_FREEBSD: + return freebsd_parse_xattr_stream(jcr, stream); +#elif defined(HAVE_LINUX_OS) + case STREAM_XATTR_LINUX: + return linux_parse_xattr_stream(jcr, stream); +#elif defined(HAVE_NETBSD_OS) + case STREAM_XATTR_NETBSD: + return netbsd_parse_xattr_stream(jcr, stream); +#endif + default: + /* + * Issue a warning and discard the message. But pretend the restore was ok. + */ + Qmsg2(jcr, M_WARNING, 0, + _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"), + jcr->last_fname, stream); + return true; + } /* end switch (stream) */ +} + +#endif diff --git a/bacula/src/filed/xattr.h b/bacula/src/filed/xattr.h new file mode 100644 index 0000000000..8044c42d0a --- /dev/null +++ b/bacula/src/filed/xattr.h @@ -0,0 +1,49 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2004-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ + +#ifndef _BACULA_XATTR_ +#define _BACULA_XATTR_ + +/* + * Magic used in the magic field of the xattr struct. + * This way we can see we encounter a valid xattr struct. + */ +#define XATTR_MAGIC 0x5C5884 + +/* + * Internal representation of an extended attribute. + */ +typedef struct xattr { + uint32_t magic; + uint32_t name_length; + char *name; + uint32_t value_length; + char *value; +} xattr_t; + +#endif diff --git a/bacula/src/lib/serial.h b/bacula/src/lib/serial.h index 4f235a2119..6151287543 100644 --- a/bacula/src/lib/serial.h +++ b/bacula/src/lib/serial.h @@ -1,13 +1,7 @@ -/* - * - * Written by John Walker, MM - * - * Version $Id$ - */ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2006 Free Software Foundation Europe e.V. + Copyright (C) 2000-2008 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. @@ -26,11 +20,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Bacula® is a registered trademark ofJohn Walker. + Bacula® is a registered trademark ofKern Sibbald. The licensor of Bacula is the Free Software Foundation Europe (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. */ +/* + * + * Written by John Walker, MM + * + * Version $Id$ + */ /* Serialisation support functions from serial.c. */ @@ -76,8 +76,8 @@ extern void unserial_string(uint8_t * * const ptr, char * const str); /* ser_length -- Determine length in bytes of serialised into a buffer x. */ -#define ser_length(x) (ser_ptr - (uint8_t *)(x)) -#define unser_length(x) (ser_ptr - (uint8_t *)(x)) +#define ser_length(x) ((uint32_t)(ser_ptr - (uint8_t *)(x))) +#define unser_length(x) ((uint32_t)(ser_ptr - (uint8_t *)(x))) /* ser_end(x, s) -- End serialisation into a buffer x of size s. */ #define ser_end(x, s) ASSERT(ser_length(x) <= (s))