A specialized class to handle ACL and XATTR in Bacula Enterprise.
The runtime consist of two parts:
1. OS independent class: XACL
2. OS dependent subclass: XACL_*
OS dependent subclasses are available for the following OS:
- Darwin (OSX)
- FreeBSD (POSIX and NFSv4/ZFS acls)
- Linux
- Solaris (POSIX and NFSv4/ZFS acls)
OS dependend subclasses in progress:
- AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
- HPUX
- IRIX
- Tru64
src/qt-console/Makefile.mingw32.Debug
src/qt-console/Makefile.mingw32.Release
src/qt-console/bat.pro.mingw32
+src/qt-console/bat.pro.mingw64
# src/qt-console/clients/
src/qt-console/clients/.*.swp
Philippe Chauvat
Phil Stracchino
Preben Guldberg
+Radoslaw Korzeniewski
Riccardo Ghetta
Richard Mortimer
Robert Nelson
#
# Bacula Makefile for the File daemon
#
-# Copyright (C) 2000-2015 Kern Sibbald
+# Copyright (C) 2000-2016 Kern Sibbald
# License: BSD 2-Clause; see file LICENSE-FOSS
#
@MCOMMON@
dummy:
#
-SVRSRCS = filed.c authenticate.c acl.c backup.c crypto.c \
+SVRSRCS = filed.c authenticate.c backup.c crypto.c \
estimate.c \
fd_plugins.c accurate.c \
filed_conf.c heartbeat.c hello.c job.c fd_snapshot.c \
- restore.c status.c verify.c verify_vol.c xattr.c
+ restore.c status.c verify.c verify_vol.c \
+ xacl.c xacl_linux.c xacl_osx.c xacl_solaris.c xacl_freebsd.c
SVROBJS = $(SVRSRCS:.c=.o)
# these are the objects that are changed by the .configure process
@echo "==== Make of filed is good ===="
@echo " "
-acl.o: acl.c
+xacl.o: xacl.c
@echo "Compiling $<"
$(NO_ECHO)$(CXX) $(DEFS) $(DEBUG) -c $(WCFLAGS) $(CPPFLAGS) $(LZO_INC) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $(AFS_CFLAGS) $<
+++ /dev/null
-/*
- Bacula(R) - The Network Backup Solution
-
- Copyright (C) 2000-2015 Kern Sibbald
- Copyright (C) 2004-2015 Free Software Foundation Europe e.V.
-
- The original author of Bacula is Kern Sibbald, with contributions
- from many others, a complete list can be found in the file AUTHORS.
-
- You may use this file and others of this release according to the
- license defined in the LICENSE file, which includes the Affero General
- Public License, v3.0 ("AGPLv3") and some additional permissions and
- terms pursuant to its AGPLv3 Section 7.
-
- This notice must be preserved when any source code is
- conveyed and/or propagated.
-
- Bacula(R) is a registered trademark of Kern Sibbald.
-*/
-/*
- * Functions to handle ACLs for bacula.
- *
- * Currently we support the following OSes:
- * - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
- * - Darwin
- * - FreeBSD (POSIX and NFSv4/ZFS acls)
- * - GNU Hurd
- * - HPUX
- * - IRIX
- * - Linux
- * - Solaris (POSIX and NFSv4/ZFS acls)
- * - Tru64
- *
- * Next to OS specific acls we support AFS acls using the pioctl interface.
- *
- * We handle two different types of ACLs: access and default ACLS.
- * On most systems that support default ACLs they only apply to directories.
- *
- * On some systems (eg. linux and FreeBSD) we must obtain the two ACLs
- * independently, while others (eg. Solaris) provide both in one call.
- *
- * The Filed saves ACLs in their native format and uses different streams
- * for all different platforms. Currently we only allow ACLs to be restored
- * which were saved in the native format of the platform they are extracted
- * on. Later on we might add conversion functions for mapping from one
- * platform to an other or allow restores of systems that use the same
- * native format.
- *
- * Its also interesting to see what the exact format of acl text is on
- * certain platforms and if they use they same encoding we might allow
- * different platform streams to be decoded on an other similar platform.
- *
- * Original written by Preben 'Peppe' Guldberg, December 2004
- *
- */
-
-#include "bacula.h"
-#include "filed.h"
-
-#if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
-/*
- * Entry points when compiled without support for ACLs or on an unsupported platform.
- */
-bool backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- Jmsg(jcr, M_FATAL, 0, "ACL backup requested but not configured in Bacula.\n");
- return false;
-}
-
-bacl_rtn_code restore_acl_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
- Jmsg(jcr, M_FATAL, 0, "ACL backup requested but not configured in Bacula.\n");
- return bacl_rtn_fatal;
-}
-#else
-/*
- * Send an ACL stream to the SD.
- */
-static bacl_rtn_code send_acl_stream(JCR *jcr, int stream)
-{
- BSOCK *sd = jcr->store_bsock;
- POOLMEM *msgsave;
-#ifdef FD_NO_SEND_TEST
- return bacl_rtn_ok;
-#endif
-
- /*
- * Sanity check
- */
- if (jcr->acl_ctx->content_length <= 0) {
- return bacl_rtn_ok;
- }
-
- /*
- * 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 bacl_rtn_fatal;
- }
-
- /*
- * Send the buffer to the storage deamon
- */
- Dmsg1(400, "Backing up ACL <%s>\n", jcr->acl_ctx->content);
- msgsave = sd->msg;
- sd->msg = jcr->acl_ctx->content;
- sd->msglen = jcr->acl_ctx->content_length + 1;
- 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 bacl_rtn_fatal;
- }
-
- 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 bacl_rtn_fatal;
- }
-
- Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
- return bacl_rtn_ok;
-}
-
-/*
- * First the native ACLs.
- */
-#if defined(HAVE_ACL)
-#if defined(HAVE_AIX_OS)
-
-#if defined(HAVE_EXTENDED_ACL)
-
-#include <sys/access.h>
-#include <sys/acl.h>
-
-static bool acl_is_trivial(struct acl *acl)
-{
- return (acl_last(acl) != acl->acl_ext ? false : true);
-}
-
-static bool acl_nfs4_is_trivial(nfs4_acl_int_t *acl)
-{
- int i;
- int count = acl->aclEntryN;
- nfs4_ace_int_t *ace;
-
- for (i = 0; i < count; i++) {
- ace = &acl->aclEntry[i];
- if (!((ace->flags & ACE4_ID_SPECIAL) != 0 &&
- (ace->aceWho.special_whoid == ACE4_WHO_OWNER ||
- ace->aceWho.special_whoid == ACE4_WHO_GROUP ||
- ace->aceWho.special_whoid == ACE4_WHO_EVERYONE) &&
- ace->aceType == ACE4_ACCESS_ALLOWED_ACE_TYPE &&
- ace->aceFlags == 0 &&
- (ace->aceMask & ~(ACE4_READ_DATA |
- ACE4_LIST_DIRECTORY |
- ACE4_WRITE_DATA |
- ACE4_ADD_FILE |
- ACE4_EXECUTE)) == 0)) {
- return false;
- }
- }
- return true;
-}
-
-/*
- * Define the supported ACL streams for this OS
- */
-static int os_access_acl_streams[3] = {
- STREAM_ACL_AIX_TEXT,
- STREAM_ACL_AIX_AIXC,
- STREAM_ACL_AIX_NFS4
-};
-static int os_default_acl_streams[1] = {
- -1
-};
-
-static bacl_rtn_code aix_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- mode_t mode;
- acl_type_t type;
- size_t aclsize, acltxtsize;
- bacl_rtn_code retval = bacl_rtn_error;
- POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
-
- /*
- * First see how big the buffers should be.
- */
- memset(&type, 0, sizeof(acl_type_t));
- type.u64 = ACL_ANY;
- if (aclx_get(jcr->last_fname, GET_ACLINFO_ONLY, &type, NULL, &aclsize, &mode) < 0) {
- berrno be;
- if (errno == ENOENT) {
- retval = bacl_rtn_ok;
- } else if (errno == ENOSYS) {
- /*
- * If the filesystem reports it doesn't support ACLs we clear the
- * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
- * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
- * when we change from one filesystem to an other.
- */
- jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
- retval = bacl_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- }
- goto get_out;
- }
-
- /*
- * Make sure the buffers are big enough.
- */
- aclbuf = check_pool_memory_size(aclbuf, aclsize + 1);
-
- /*
- * Retrieve the ACL info.
- */
- if (aclx_get(jcr->last_fname, 0, &type, aclbuf, &aclsize, &mode) < 0) {
- berrno be;
- if (errno == ENOENT) {
- retval = bacl_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("aclx_get error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- }
- goto get_out;
- }
-
- /*
- * See if the acl is non trivial.
- */
- switch (type.u64) {
- case ACL_AIXC:
- if (acl_is_trivial((struct acl *)aclbuf)) {
- retval = bacl_rtn_ok;
- goto get_out;
- }
- break;
- case ACL_NFS4:
- if (acl_nfs4_is_trivial((nfs4_acl_int_t *)aclbuf)) {
- retval = bacl_rtn_ok;
- goto get_out;
- }
- break;
- default:
- Mmsg2(jcr->errmsg, _("Unknown acl type encountered on file \"%s\": %ld\n"),
- jcr->last_fname, type.u64);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * We have a non-trivial acl lets convert it into some ASCII form.
- */
- acltxtsize = sizeof_pool_memory(jcr->acl_ctx->content);
- if (aclx_printStr(jcr->acl_ctx->content, &acltxtsize, aclbuf,
- aclsize, type, jcr->last_fname, 0) < 0) {
- if (errno == ENOSPC) {
- /*
- * Our buffer is not big enough, acltxtsize should be updated with the value
- * the aclx_printStr really need. So we increase the buffer and try again.
- */
- jcr->acl_ctx->content = check_pool_memory_size(jcr->acl_ctx->content, acltxtsize + 1);
- if (aclx_printStr(jcr->acl_ctx->content, &acltxtsize, aclbuf,
- aclsize, type, jcr->last_fname, 0) < 0) {
- Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- } else {
- Mmsg1(jcr->errmsg, _("Failed to convert acl into text on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
- jcr->acl_ctx->content_length = strlen(jcr->acl_ctx->content) + 1;
- switch (type.u64) {
- case ACL_AIXC:
- retval = send_acl_stream(jcr, STREAM_ACL_AIX_AIXC);
- break;
- case ACL_NFS4:
- retval = send_acl_stream(jcr, STREAM_ACL_AIX_NFS4);
- break;
- }
-
-get_out:
- free_pool_memory(aclbuf);
-
- return retval;
-}
-
-/*
- * See if a specific type of ACLs are supported on the filesystem
- * the file is located on.
- */
-static inline bool aix_query_acl_support(JCR *jcr,
- uint64_t aclType,
- acl_type_t *pacl_type_info)
-{
- unsigned int i;
- acl_types_list_t acl_type_list;
- size_t acl_type_list_len = sizeof(acl_types_list_t);
-
- memset(&acl_type_list, 0, sizeof(acl_type_list));
- if (aclx_gettypes(jcr->last_fname, &acl_type_list, &acl_type_list_len)) {
- return false;
- }
-
- for (i = 0; i < acl_type_list.num_entries; i++) {
- if (acl_type_list.entries[i].u64 == aclType) {
- memcpy(pacl_type_info, acl_type_list.entries + i, sizeof(acl_type_t));
- return true;
- }
- }
- return false;
-}
-
-static bacl_rtn_code aix_restore_acl_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
- int cnt;
- acl_type_t type;
- size_t aclsize;
- bacl_rtn_code retval = bacl_rtn_error;
- POOLMEM *aclbuf = get_pool_memory(PM_MESSAGE);
-
- switch (stream) {
- case STREAM_ACL_AIX_TEXT:
- /*
- * Handle the old stream using the old system call for now.
- */
- if (acl_put(jcr->last_fname, content, 0) != 0) {
- retval = bacl_rtn_error;
- goto get_out;
- }
- retval = bacl_rtn_ok;
- goto get_out;
- case STREAM_ACL_AIX_AIXC:
- if (!aix_query_acl_support(jcr, ACL_AIXC, &type)) {
- Mmsg1(jcr->errmsg,
- _("Trying to restore POSIX acl on file \"%s\" on filesystem without AIXC acl support\n"),
- jcr->last_fname);
- goto get_out;
- }
- break;
- case STREAM_ACL_AIX_NFS4:
- if (!aix_query_acl_support(jcr, ACL_NFS4, &type)) {
- Mmsg1(jcr->errmsg,
- _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without NFS4 acl support\n"),
- jcr->last_fname);
- goto get_out;
- }
- break;
- default:
- goto get_out;
- }
-
- /*
- * Set the acl buffer to an initial size. For now we set it
- * to the same size as the ASCII representation.
- */
- aclbuf = check_pool_memory_size(aclbuf, content_length);
- aclsize = content_length;
- if (aclx_scanStr(content, aclbuf, &aclsize, type) < 0) {
- berrno be;
- if (errno == ENOSPC) {
- /*
- * The buffer isn't big enough. The man page doesn't say that aclsize
- * is updated to the needed size as what is done with aclx_printStr.
- * So for now we try to increase the buffer a maximum of 3 times
- * and retry the conversion.
- */
- for (cnt = 0; cnt < 3; cnt++) {
- aclsize = 2 * aclsize;
- aclbuf = check_pool_memory_size(aclbuf, aclsize);
-
- if (aclx_scanStr(content, aclbuf, &aclsize, type) == 0) {
- break;
- }
-
- /*
- * See why we failed this time, ENOSPC retry if max retries not met,
- * otherwise abort.
- */
- if (errno == ENOSPC && cnt < 3) {
- continue;
- }
- Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror(errno));
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- } else {
- Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out
- }
- }
-
- if (aclx_put(jcr->last_fname, SET_ACL, type, aclbuf, aclsize, 0) < 0) {
- berrno be;
- if (errno == ENOENT) {
- retval = bacl_rtn_ok;
- } else if (ENOSYS) {
- /*
- * If the filesystem reports it doesn't support ACLs we clear the
- * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
- * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
- * when we change from one filesystem to an other.
- */
- jcr->acl_ctx->flags &= ~BACL_FLAG_RESTORE_NATIVE;
- } else {
- Mmsg2(jcr->errmsg, _("aclx_put error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
- retval = bacl_rtn_ok;
-
-get_out:
- free_pool_memory(aclbuf);
- return retval;
-}
-
-#else /* HAVE_EXTENDED_ACL */
-
-#include <sys/access.h>
-
-/*
- * Define the supported ACL streams for this OS
- */
-static int os_access_acl_streams[1] = {
- STREAM_ACL_AIX_TEXT
-};
-static int os_default_acl_streams[1] = {
- -1
-};
-
-static bacl_rtn_code aix_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- char *acl_text;
-
- if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
- jcr->acl_ctx->content_length =
- pm_strcpy(jcr->acl_ctx->content, acl_text);
- actuallyfree(acl_text);
- return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
- }
- return bacl_rtn_error;
-}
-
-static bacl_rtn_code aix_restore_acl_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
- if (acl_put(jcr->last_fname, content, 0) != 0) {
- return bacl_rtn_error;
- }
- return bacl_rtn_ok;
-}
-#endif /* HAVE_EXTENDED_ACL */
-
-/*
- * For this OS setup the build and parse function pointer to the OS specific functions.
- */
-static bacl_rtn_code (*os_backup_acl_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- aix_backup_acl_streams;
-static bacl_rtn_code (*os_restore_acl_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- aix_restore_acl_streams;
-
-#elif defined(HAVE_DARWIN_OS) || \
- defined(HAVE_FREEBSD_OS) || \
- defined(HAVE_IRIX_OS) || \
- defined(HAVE_OSF1_OS) || \
- defined(HAVE_LINUX_OS) || \
- defined(HAVE_HURD_OS)
-
-#include <sys/types.h>
-
-#ifdef HAVE_SYS_ACL_H
-#include <sys/acl.h>
-#else
-#error "configure failed to detect availability of sys/acl.h"
-#endif
-
-/*
- * On IRIX we can get shortened ACLs
- */
-#if defined(HAVE_IRIX_OS) && defined(BACL_WANT_SHORT_ACLS)
-#define acl_to_text(acl,len) acl_to_short_text((acl), (len))
-#endif
-
-/*
- * On Linux we can get numeric and/or shorted ACLs
- */
-#if defined(HAVE_LINUX_OS)
-#if defined(BACL_WANT_SHORT_ACLS) && defined(BACL_WANT_NUMERIC_IDS)
-#define BACL_ALTERNATE_TEXT (TEXT_ABBREVIATE|TEXT_NUMERIC_IDS)
-#elif defined(BACL_WANT_SHORT_ACLS)
-#define BACL_ALTERNATE_TEXT TEXT_ABBREVIATE
-#elif defined(BACL_WANT_NUMERIC_IDS)
-#define BACL_ALTERNATE_TEXT TEXT_NUMERIC_IDS
-#endif
-#ifdef BACL_ALTERNATE_TEXT
-#include <acl/libacl.h>
-#define acl_to_text(acl,len) (acl_to_any_text((acl), NULL, ',', BACL_ALTERNATE_TEXT))
-#endif
-#endif
-
-/*
- * On FreeBSD we can get numeric ACLs
- */
-#if defined(HAVE_FREEBSD_OS)
-#if defined(BACL_WANT_NUMERIC_IDS)
-#define BACL_ALTERNATE_TEXT ACL_TEXT_NUMERIC_IDS
-#endif
-#ifdef BACL_ALTERNATE_TEXT
-#define acl_to_text(acl,len) (acl_to_text_np((acl), (len), BACL_ALTERNATE_TEXT))
-#endif
-#endif
-
-/*
- * Some generic functions used by multiple OSes.
- */
-static acl_type_t bac_to_os_acltype(bacl_type acltype)
-{
- acl_type_t ostype;
-
- switch (acltype) {
- case BACL_TYPE_ACCESS:
- ostype = ACL_TYPE_ACCESS;
- break;
- case BACL_TYPE_DEFAULT:
- ostype = ACL_TYPE_DEFAULT;
- break;
-#ifdef HAVE_ACL_TYPE_NFS4
- /*
- * FreeBSD has an additional acl type named ACL_TYPE_NFS4.
- */
- case BACL_TYPE_NFS4:
- ostype = ACL_TYPE_NFS4;
- break;
-#endif
-#ifdef HAVE_ACL_TYPE_DEFAULT_DIR
- case BACL_TYPE_DEFAULT_DIR:
- /*
- * TRU64 has an additional acl type named ACL_TYPE_DEFAULT_DIR.
- */
- ostype = ACL_TYPE_DEFAULT_DIR;
- break;
-#endif
-#ifdef HAVE_ACL_TYPE_EXTENDED
- case BACL_TYPE_EXTENDED:
- /*
- * MacOSX has an additional acl type named ACL_TYPE_EXTENDED.
- */
- ostype = ACL_TYPE_EXTENDED;
- break;
-#endif
- default:
- /*
- * This should never happen, as the per OS version function only tries acl
- * types supported on a certain platform.
- */
- ostype = (acl_type_t)ACL_TYPE_NONE;
- break;
- }
- return ostype;
-}
-
-static int acl_count_entries(acl_t acl)
-{
- int count = 0;
-#if defined(HAVE_FREEBSD_OS) || \
- defined(HAVE_LINUX_OS) || \
- defined(HAVE_HURD_OS)
- acl_entry_t ace;
- int entry_available;
-
- entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
- while (entry_available == 1) {
- count++;
- entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
- }
-#elif defined(HAVE_IRIX_OS)
- count = acl->acl_cnt;
-#elif defined(HAVE_OSF1_OS)
- count = acl->acl_num;
-#elif defined(HAVE_DARWIN_OS)
- acl_entry_t ace;
- int entry_available;
-
- entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
- while (entry_available == 0) {
- count++;
- entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
- }
-#endif
- return count;
-}
-
-#if !defined(HAVE_DARWIN_OS)
-/*
- * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
- * There is no need to store those acls as we already store the stat bits too.
- */
-static bool acl_is_trivial(acl_t acl)
-{
- /*
- * acl is trivial if it has only the following entries:
- * "user::",
- * "group::",
- * "other::"
- */
- acl_entry_t ace;
- acl_tag_t tag;
-#if defined(HAVE_FREEBSD_OS) || \
- defined(HAVE_LINUX_OS) || \
- defined(HAVE_HURD_OS)
- int entry_available;
-
- entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
- while (entry_available == 1) {
- /*
- * Get the tag type of this acl entry.
- * If we fail to get the tagtype we call the acl non-trivial.
- */
- if (acl_get_tag_type(ace, &tag) < 0)
- return true;
- /*
- * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
- */
- if (tag != ACL_USER_OBJ &&
- tag != ACL_GROUP_OBJ &&
- tag != ACL_OTHER)
- return false;
- entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
- }
- return true;
-#elif defined(HAVE_IRIX_OS)
- int n;
-
- for (n = 0; n < acl->acl_cnt; n++) {
- ace = &acl->acl_entry[n];
- tag = ace->ae_tag;
-
- /*
- * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
- */
- if (tag != ACL_USER_OBJ &&
- tag != ACL_GROUP_OBJ &&
- tag != ACL_OTHER_OBJ)
- return false;
- }
- return true;
-#elif defined(HAVE_OSF1_OS)
- int count;
-
- ace = acl->acl_first;
- count = acl->acl_num;
-
- while (count > 0) {
- tag = ace->entry->acl_type;
- /*
- * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
- */
- if (tag != ACL_USER_OBJ &&
- tag != ACL_GROUP_OBJ &&
- tag != ACL_OTHER)
- return false;
- /*
- * On Tru64, perm can also contain non-standard bits such as
- * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
- */
- if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
- return false;
- ace = ace->next;
- count--;
- }
- return true;
-#endif
-}
-#endif
-
-/*
- * Generic wrapper around acl_get_file call.
- */
-static bacl_rtn_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
-{
- acl_t acl;
- acl_type_t ostype;
- char *acl_text;
- bacl_rtn_code retval = bacl_rtn_ok;
-
- ostype = bac_to_os_acltype(acltype);
- acl = acl_get_file(jcr->last_fname, ostype);
- if (acl) {
- /*
- * From observation, IRIX's acl_get_file() seems to return a
- * non-NULL acl with a count field of -1 when a file has no ACL
- * defined, while IRIX's acl_to_text() returns NULL when presented
- * with such an ACL.
- *
- * For all other implmentations we check if there are more then
- * zero entries in the acl returned.
- */
- if (acl_count_entries(acl) <= 0) {
- goto get_out;
- }
-
- /*
- * Make sure this is not just a trivial ACL.
- */
-#ifndef HAVE_DARWIN_OS
- if (acltype == BACL_TYPE_ACCESS && acl_is_trivial(acl)) {
- /*
- * The ACLs simply reflect the (already known) standard permissions
- * So we don't send an ACL stream to the SD.
- */
- goto get_out;
- }
-#endif
-
-#if defined(HAVE_FREEBSD_OS) && defined(_PC_ACL_NFS4)
- if (acltype == BACL_TYPE_NFS4) {
- int trivial;
- if (acl_is_trivial_np(acl, &trivial) == 0) {
- /* Trivial ACLS are standard permissions. Do not send to SD. */
- if (trivial == 1) {
- goto get_out;
- }
- }
- }
-#endif
-
- /*
- * Convert the internal acl representation into a text representation.
- */
- if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
- jcr->acl_ctx->content_length =
- pm_strcpy(jcr->acl_ctx->content, acl_text);
- acl_free(acl);
- acl_free(acl_text);
- return bacl_rtn_ok;
- }
-
- berrno be;
- Mmsg2(jcr->errmsg,
- _("acl_to_text error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- retval = bacl_rtn_error;
- } else {
- berrno be;
-
- /*
- * Handle errors gracefully.
- */
- switch (errno) {
- case BACL_ENOTSUP:
- /*
- * If the filesystem reports it doesn't support ACLs we clear the
- * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
- * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
- * when we change from one filesystem to an other.
- */
- jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
- break;
- case ENOENT:
- break;
- default:
- /* Some real error */
- Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- retval = bacl_rtn_error;
- break;
- }
- }
-
-get_out:
- if (acl) {
- acl_free(acl);
- }
- pm_strcpy(jcr->acl_ctx->content, "");
- jcr->acl_ctx->content_length = 0;
- return retval;
-}
-
-/*
- * Generic wrapper around acl_set_file call.
- */
-static bacl_rtn_code generic_set_acl_on_os(JCR *jcr,
- bacl_type acltype,
- char *content,
- uint32_t content_length)
-{
- acl_t acl;
- acl_type_t ostype;
-
- /*
- * If we get empty default ACLs, clear ACLs now
- */
- ostype = bac_to_os_acltype(acltype);
- if (ostype == ACL_TYPE_DEFAULT && strlen(content) == 0) {
- if (acl_delete_def_file(jcr->last_fname) == 0) {
- return bacl_rtn_ok;
- }
- berrno be;
-
- switch (errno) {
- case ENOENT:
- return bacl_rtn_ok;
- case BACL_ENOTSUP:
- /*
- * If the filesystem reports it doesn't support ACLs we clear the
- * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
- * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
- * when we change from one filesystem to an other.
- */
- jcr->acl_ctx->flags &= ~BACL_FLAG_RESTORE_NATIVE;
- Mmsg1(jcr->errmsg,
- _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"),
- jcr->last_fname);
- return bacl_rtn_error;
- default:
- Mmsg2(jcr->errmsg,
- _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- return bacl_rtn_error;
- }
- }
-
- acl = acl_from_text(content);
- if (acl == NULL) {
- berrno be;
-
- Mmsg2(jcr->errmsg,
- _("acl_from_text error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
-
-#ifndef HAVE_FREEBSD_OS
- /*
- * FreeBSD always fails acl_valid() - at least on valid input...
- * As it does the right thing, given valid input, just ignore acl_valid().
- */
- if (acl_valid(acl) != 0) {
- berrno be;
-
- Mmsg2(jcr->errmsg,
- _("acl_valid error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- acl_free(acl);
- return bacl_rtn_error;
- }
-#endif
-
- /*
- * Restore the ACLs, but don't complain about links which really should
- * not have attributes, and the file it is linked to may not yet be restored.
- * This is only true for the old acl streams as in the new implementation we
- * don't save acls of symlinks (which cannot have acls anyhow)
- */
- if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
- berrno be;
- switch (errno) {
- case ENOENT:
- acl_free(acl);
- return bacl_rtn_ok;
- case BACL_ENOTSUP:
- /*
- * If the filesystem reports it doesn't support ACLs we clear the
- * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
- * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
- * when we change from one filesystem to an other.
- */
- jcr->acl_ctx->flags &= ~BACL_FLAG_RESTORE_NATIVE;
- Mmsg1(jcr->errmsg,
- _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- acl_free(acl);
- return bacl_rtn_error;
- default:
- Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- acl_free(acl);
- return bacl_rtn_error;
- }
- }
- acl_free(acl);
- return bacl_rtn_ok;
-}
-
-/*
- * OS specific functions for handling different types of acl streams.
- */
-#if defined(HAVE_DARWIN_OS)
-/*
- * Define the supported ACL streams for this OS
- */
-static int os_access_acl_streams[1] = {
- STREAM_ACL_DARWIN_ACCESS
-};
-static int os_default_acl_streams[1] = {
- -1
-};
-
-static bacl_rtn_code darwin_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
-#if defined(HAVE_ACL_TYPE_EXTENDED)
- /*
- * On MacOS X, acl_get_file (name, ACL_TYPE_ACCESS)
- * and acl_get_file (name, ACL_TYPE_DEFAULT)
- * always return NULL / EINVAL. There is no point in making
- * these two useless calls. The real ACL is retrieved through
- * acl_get_file (name, ACL_TYPE_EXTENDED).
- *
- * Read access ACLs for files, dirs and links
- */
- if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_rtn_fatal)
- return bacl_rtn_fatal;
-#else
- /*
- * Read access ACLs for files, dirs and links
- */
- if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_rtn_fatal)
- return bacl_rtn_fatal;
-#endif
-
- if (jcr->acl_ctx->content_length > 0) {
- return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS);
- }
- return bacl_rtn_ok;
-}
-
-static bacl_rtn_code darwin_restore_acl_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
-#if defined(HAVE_ACL_TYPE_EXTENDED)
- return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED, content, content_length);
-#else
- return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
-#endif
-}
-
-/*
- * For this OS setup the build and parse function pointer to the OS specific functions.
- */
-static bacl_rtn_code (*os_backup_acl_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- darwin_backup_acl_streams;
-static bacl_rtn_code (*os_restore_acl_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- darwin_restore_acl_streams;
-
-#elif defined(HAVE_FREEBSD_OS)
-/*
- * Define the supported ACL streams for these OSes
- */
-static int os_access_acl_streams[2] = {
- STREAM_ACL_FREEBSD_ACCESS,
- STREAM_ACL_FREEBSD_NFS4
-};
-static int os_default_acl_streams[1] = {
- STREAM_ACL_FREEBSD_DEFAULT
-};
-
-static bacl_rtn_code freebsd_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- int acl_enabled = 0;
- bacl_type acltype = BACL_TYPE_NONE;
-
-#if defined(_PC_ACL_NFS4)
- /*
- * See if filesystem supports NFS4 acls.
- */
- acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
- if (acl_enabled < 0) {
- berrno be;
- if (errno == ENOENT) {
- return bacl_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- } else if (acl_enabled != 0) {
- acltype = BACL_TYPE_NFS4;
- }
-#endif
-
- if (acl_enabled == 0) {
- /*
- * See if filesystem supports POSIX acls.
- */
- acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
- if (acl_enabled < 0) {
- berrno be;
- if (errno == ENOENT) {
- return bacl_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- } else if (acl_enabled != 0) {
- acltype = BACL_TYPE_ACCESS;
- }
- }
-
- /*
- * If the filesystem reports it doesn't support ACLs we clear the
- * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
- * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
- * when we change from one filesystem to an other.
- */
- if (acl_enabled == 0) {
- jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
- pm_strcpy(jcr->acl_ctx->content, "");
- jcr->acl_ctx->content_length = 0;
- return bacl_rtn_ok;
- }
-
- /*
- * Based on the supported ACLs retrieve and store them.
- */
- switch (acltype) {
- case BACL_TYPE_NFS4:
- /*
- * Read NFS4 ACLs for files, dirs and links
- */
- if (generic_get_acl_from_os(jcr, BACL_TYPE_NFS4) == bacl_rtn_fatal)
- return bacl_rtn_fatal;
-
- if (jcr->acl_ctx->content_length > 0) {
- if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_NFS4) == bacl_rtn_fatal)
- return bacl_rtn_fatal;
- }
- break;
- case BACL_TYPE_ACCESS:
- /*
- * Read access ACLs for files, dirs and links
- */
- if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_rtn_fatal)
- return bacl_rtn_fatal;
-
- if (jcr->acl_ctx->content_length > 0) {
- if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS) == bacl_rtn_fatal)
- return bacl_rtn_fatal;
- }
-
- /*
- * Directories can have default ACLs too
- */
- if (ff_pkt->type == FT_DIREND) {
- if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_rtn_fatal)
- return bacl_rtn_fatal;
- if (jcr->acl_ctx->content_length > 0) {
- if (send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT) == bacl_rtn_fatal)
- return bacl_rtn_fatal;
- }
- }
- break;
- default:
- break;
- }
-
- return bacl_rtn_ok;
-}
-
-static bacl_rtn_code freebsd_restore_acl_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
- int acl_enabled = 0;
- const char *acl_type_name;
-
- /*
- * First make sure the filesystem supports acls.
- */
- switch (stream) {
- case STREAM_UNIX_ACCESS_ACL:
- case STREAM_ACL_FREEBSD_ACCESS:
- case STREAM_UNIX_DEFAULT_ACL:
- case STREAM_ACL_FREEBSD_DEFAULT:
- acl_enabled = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
- acl_type_name = "POSIX";
- break;
- case STREAM_ACL_FREEBSD_NFS4:
-#if defined(_PC_ACL_NFS4)
- acl_enabled = pathconf(jcr->last_fname, _PC_ACL_NFS4);
-#endif
- acl_type_name = "NFS4";
- break;
- default:
- acl_type_name = "unknown";
- break;
- }
-
- if (acl_enabled < 0) {
- berrno be;
- if (errno == ENOENT) {
- return bacl_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- } else if (acl_enabled == 0) {
- /*
- * If the filesystem reports it doesn't support ACLs we clear the
- * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
- * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
- * when we change from one filesystem to an other.
- */
- jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
- Mmsg2(jcr->errmsg,
- _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"),
- jcr->last_fname, acl_type_name);
- return bacl_rtn_error;
- }
-
- /*
- * Restore the ACLs.
- */
- switch (stream) {
- case STREAM_UNIX_ACCESS_ACL:
- case STREAM_ACL_FREEBSD_ACCESS:
- return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
- case STREAM_UNIX_DEFAULT_ACL:
- case STREAM_ACL_FREEBSD_DEFAULT:
- return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
- case STREAM_ACL_FREEBSD_NFS4:
- return generic_set_acl_on_os(jcr, BACL_TYPE_NFS4, content, content_length);
- default:
- break;
- }
- return bacl_rtn_error;
-}
-
-/*
- * For this OSes setup the build and parse function pointer to the OS specific functions.
- */
-static bacl_rtn_code (*os_backup_acl_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- freebsd_backup_acl_streams;
-static bacl_rtn_code (*os_restore_acl_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- freebsd_restore_acl_streams;
-
-#elif defined(HAVE_IRIX_OS) || \
- defined(HAVE_LINUX_OS) || \
- defined(HAVE_HURD_OS)
-/*
- * Define the supported ACL streams for these OSes
- */
-#if defined(HAVE_IRIX_OS)
-static int os_access_acl_streams[1] = {STREAM_ACL_IRIX_ACCESS_ACL};
-static int os_default_acl_streams[1] = {STREAM_ACL_IRIX_DEFAULT_ACL};
-#elif defined(HAVE_LINUX_OS)
-static int os_access_acl_streams[1] = {STREAM_ACL_LINUX_ACCESS};
-static int os_default_acl_streams[1] = {STREAM_ACL_LINUX_DEFAULT};
-#elif defined(HAVE_HURD_OS)
-static int os_access_acl_streams[1] = {STREAM_ACL_HURD_ACCESS};
-static int os_default_acl_streams[1] = {STREAM_ACL_HURD_DEFAULT};
-#endif
-
-static bacl_rtn_code generic_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- /*
- * Read access ACLs for files, dirs and links
- */
- if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_rtn_fatal)
- return bacl_rtn_fatal;
-
- if (jcr->acl_ctx->content_length > 0) {
- if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_rtn_fatal)
- return bacl_rtn_fatal;
- }
-
- /*
- * Directories can have default ACLs too
- */
- if (ff_pkt->type == FT_DIREND) {
- if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_rtn_fatal)
- return bacl_rtn_fatal;
- if (jcr->acl_ctx->content_length > 0) {
- if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_rtn_fatal)
- return bacl_rtn_fatal;
- }
- }
- return bacl_rtn_ok;
-}
-
-static bacl_rtn_code generic_restore_acl_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
- unsigned int cnt;
-
- switch (stream) {
- case STREAM_UNIX_ACCESS_ACL:
- return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
- case STREAM_UNIX_DEFAULT_ACL:
- return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
- default:
- /*
- * See what type of acl it is.
- */
- for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
- if (os_access_acl_streams[cnt] == stream) {
- return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
- }
- }
- for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
- if (os_default_acl_streams[cnt] == stream) {
- return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
- }
- }
- break;
- }
- return bacl_rtn_error;
-}
-
-/*
- * For this OSes setup the build and parse function pointer to the OS specific functions.
- */
-static bacl_rtn_code (*os_backup_acl_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- generic_backup_acl_streams;
-static bacl_rtn_code (*os_restore_acl_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- generic_restore_acl_streams;
-
-#elif defined(HAVE_OSF1_OS)
-
-/*
- * Define the supported ACL streams for this OS
- */
-static int os_access_acl_streams[1] = {
- STREAM_ACL_TRU64_ACCESS
-};
-static int os_default_acl_streams[2] = {
- STREAM_ACL_TRU64_DEFAULT,
- STREAM_ACL_TRU64_DEFAULT_DIR
-};
-
-static bacl_rtn_code tru64_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- /*
- * Read access ACLs for files, dirs and links
- */
- if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_rtn_fatal) {
- return bacl_rtn_error;
- if (jcr->acl_ctx->content_length > 0) {
- if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
- return bacl_rtn_error;
- }
- /*
- * Directories can have default ACLs too
- */
- if (ff_pkt->type == FT_DIREND) {
- if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_rtn_fatal) {
- return bacl_rtn_error;
- if (jcr->acl_ctx->content_length > 0) {
- if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
- return bacl_rtn_error;
- }
- /*
- * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
- * This is an inherited acl for all subdirs.
- * See http://www.helsinki.fi/atk/unix/dec_manuals/DOC_40D/AQ0R2DTE/DOCU_018.HTM
- * Section 21.5 Default ACLs
- */
- if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR) == bacl_rtn_fatal) {
- return bacl_rtn_error;
- if (jcr->acl_ctx->content_length > 0) {
- if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
- return bacl_rtn_error;
- }
- }
- return bacl_rtn_ok;
-}
-
-static bacl_rtn_code tru64_restore_acl_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
- switch (stream) {
- case STREAM_UNIX_ACCESS_ACL:
- case STREAM_ACL_TRU64_ACCESS_ACL:
- return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS, content, content_length);
- case STREAM_UNIX_DEFAULT_ACL:
- case STREAM_ACL_TRU64_DEFAULT_ACL:
- return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT, content, content_length);
- case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
- return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR, content, content_length);
-}
-
-/*
- * For this OS setup the build and parse function pointer to the OS specific functions.
- */
-static bacl_rtn_code (*os_backup_acl_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- tru64_backup_acl_streams;
-static bacl_rtn_code (*os_restore_acl_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- tru64_restore_acl_streams;
-
-#endif
-
-#elif defined(HAVE_HPUX_OS)
-#ifdef HAVE_SYS_ACL_H
-#include <sys/acl.h>
-#else
-#error "configure failed to detect availability of sys/acl.h"
-#endif
-
-#include <acllib.h>
-
-/*
- * Define the supported ACL streams for this OS
- */
-static int os_access_acl_streams[1] = {
- STREAM_ACL_HPUX_ACL_ENTRY
-};
-static int os_default_acl_streams[1] = {
- -1
-};
-
-/*
- * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
- * There is no need to store those acls as we already store the stat bits too.
- */
-static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
-{
- int n;
- struct acl_entry ace
-
- for (n = 0; n < count; n++) {
- ace = entries[n];
- /*
- * See if this acl just is the stat mode in acl form.
- */
- if (!((ace.uid == sb.st_uid && ace.gid == ACL_NSGROUP) ||
- (ace.uid == ACL_NSUSER && ace.gid == sb.st_gid) ||
- (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
- return false;
- }
- return true;
-}
-
-/*
- * OS specific functions for handling different types of acl streams.
- */
-static bacl_rtn_code hpux_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- int n;
- struct acl_entry acls[NACLENTRIES];
- char *acl_text;
-
- if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
- berrno be;
- switch (errno) {
- case BACL_ENOTSUP:
- /*
- * Not supported, just pretend there is nothing to see
- *
- * If the filesystem reports it doesn't support ACLs we clear the
- * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
- * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
- * when we change from one filesystem to an other.
- */
- jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
- pm_strcpy(jcr->acl_ctx->content, "");
- jcr->acl_ctx->content_length = 0;
- return bacl_rtn_ok;
- case ENOENT:
- pm_strcpy(jcr->acl_ctx->content, "");
- jcr->acl_ctx->content_length = 0;
- return bacl_rtn_ok;
- default:
- Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- pm_strcpy(jcr->acl_ctx->content, "");
- jcr->acl_ctx->content_length = 0;
- return bacl_rtn_error;
- }
- }
- if (n == 0) {
- pm_strcpy(jcr->acl_ctx->content, "");
- jcr->acl_ctx->content_length = 0;
- return bacl_rtn_ok;
- }
- if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
- if (acl_is_trivial(n, acls, ff_pkt->statp)) {
- /*
- * The ACLs simply reflect the (already known) standard permissions
- * So we don't send an ACL stream to the SD.
- */
- pm_strcpy(jcr->acl_ctx->content, "");
- jcr->acl_ctx->content_length = 0;
- return bacl_rtn_ok;
- }
- if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
- jcr->acl_ctx->content_length =
- pm_strcpy(jcr->acl_ctx->content, acl_text);
- actuallyfree(acl_text);
-
- return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
- }
-
- berrno be;
- Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- return bacl_rtn_error;
-}
-
-static bacl_rtn_code hpux_restore_acl_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
- int n, stat;
- struct acl_entry acls[NACLENTRIES];
-
- n = strtoacl(content, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
- if (n <= 0) {
- berrno be;
- Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- if (strtoacl(content, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
- berrno be;
- Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- /*
- * Restore the ACLs, but don't complain about links which really should
- * not have attributes, and the file it is linked to may not yet be restored.
- * This is only true for the old acl streams as in the new implementation we
- * don't save acls of symlinks (which cannot have acls anyhow)
- */
- if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- return bacl_rtn_ok;
- case BACL_ENOTSUP:
- /*
- * If the filesystem reports it doesn't support ACLs we clear the
- * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
- * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
- * when we change from one filesystem to an other.
- */
- jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
- Mmsg1(jcr->errmsg,
- _("setacl error on file \"%s\": filesystem doesn't support ACLs\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- default:
- Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- }
- return bacl_rtn_ok;
-}
-
-/*
- * For this OS setup the build and parse function pointer to the OS specific functions.
- */
-static bacl_rtn_code (*os_backup_acl_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- hpux_backup_acl_streams;
-
-static bacl_rtn_code (*os_restore_acl_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- hpux_restore_acl_streams;
-
-#elif defined(HAVE_SUN_OS)
-#ifdef HAVE_SYS_ACL_H
-#include <sys/acl.h>
-#else
-#error "configure failed to detect availability of sys/acl.h"
-#endif
-
-#if defined(HAVE_EXTENDED_ACL)
-/*
- * We define some internals of the Solaris acl libs here as those
- * are not exposed yet. Probably because they want us to see the
- * acls as opague data. But as we need to support different platforms
- * and versions of Solaris we need to expose some data to be able
- * to determine the type of acl used to stuff it into the correct
- * data stream. I know this is far from portable, but maybe the
- * proper interface is exposed later on and we can get ride of
- * this kludge. Newer versions of Solaris include sys/acl_impl.h
- * which has implementation details of acls, if thats included we
- * don't have to define it ourself.
- */
-#if !defined(_SYS_ACL_IMPL_H)
-typedef enum acl_type {
- ACLENT_T = 0,
- ACE_T = 1
-} acl_type_t;
-#endif
-
-/*
- * Two external references to functions in the libsec library function not in current include files.
- */
-extern "C" {
-int acl_type(acl_t *);
-char *acl_strerror(int);
-}
-
-/*
- * Define the supported ACL streams for this OS
- */
-static int os_access_acl_streams[2] = {
- STREAM_ACL_SOLARIS_POSIX,
- STREAM_ACL_SOLARIS_NFS4
-};
-static int os_default_acl_streams[1] = {
- -1
-};
-
-/*
- * As the new libsec interface with acl_totext and acl_fromtext also handles
- * the old format from acltotext we can use the new functions even
- * for acls retrieved and stored in the database with older fd versions. If the
- * new interface is not defined (Solaris 9 and older we fall back to the old code)
- */
-static bacl_rtn_code solaris_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- int acl_enabled, flags;
- acl_t *aclp;
- char *acl_text;
- bacl_rtn_code stream_status = bacl_rtn_error;
-
- /*
- * See if filesystem supports acls.
- */
- acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
- if (acl_enabled == 0) {
- /*
- * If the filesystem reports it doesn't support ACLs we clear the
- * BACL_FLAG_SAVE_NATIVE flag so we skip ACL saves on all other files
- * on the same filesystem. The BACL_FLAG_SAVE_NATIVE flag gets set again
- * when we change from one filesystem to an other.
- */
- jcr->acl_ctx->flags &= ~BACL_FLAG_SAVE_NATIVE;
- pm_strcpy(jcr->acl_ctx->content, "");
- jcr->acl_ctx->content_length = 0;
- return bacl_rtn_ok;
- }
- if (acl_enabled < 0) {
- berrno be;
- if (errno == ENOENT) {
- return bacl_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- }
-
- /*
- * Get ACL info: don't bother allocating space if there is only a trivial ACL.
- */
- if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
- berrno be;
- if (errno == ENOENT) {
- return bacl_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, acl_strerror(errno));
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- }
-
- if (!aclp) {
- /*
- * The ACLs simply reflect the (already known) standard permissions
- * So we don't send an ACL stream to the SD.
- */
- pm_strcpy(jcr->acl_ctx->content, "");
- jcr->acl_ctx->content_length = 0;
- return bacl_rtn_ok;
- }
-
-#if defined(ACL_SID_FMT)
- /*
- * New format flag added in newer Solaris versions.
- */
- flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
-#else
- flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
-#endif /* ACL_SID_FMT */
-
- if ((acl_text = acl_totext(aclp, flags)) != NULL) {
- jcr->acl_ctx->content_length =
- pm_strcpy(jcr->acl_ctx->content, acl_text);
- actuallyfree(acl_text);
-
- switch (acl_type(aclp)) {
- case ACLENT_T:
- stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_POSIX);
- break;
- case ACE_T:
- stream_status = send_acl_stream(jcr, STREAM_ACL_SOLARIS_NFS4);
- break;
- default:
- break;
- }
-
- acl_free(aclp);
- }
- return stream_status;
-}
-
-static bacl_rtn_code solaris_restore_acl_streams(JCR *jcr, int stream, char *content,
- uint32_t content_length)
-{
- acl_t *aclp;
- int acl_enabled, error;
-
- if (stream != STREAM_UNIX_ACCESS_ACL || stream != STREAM_ACL_SOLARIS_POSIX ||
- stream != STREAM_ACL_SOLARIS_NFS4) {
- return bacl_rtn_error;
- }
-
- /*
- * First make sure the filesystem supports acls.
- */
- acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
- if (acl_enabled == 0) {
- /*
- * If the filesystem reports it doesn't support ACLs we clear the
- * BACL_FLAG_RESTORE_NATIVE flag so we skip ACL restores on all other files
- * on the same filesystem. The BACL_FLAG_RESTORE_NATIVE flag gets set again
- * when we change from one filesystem to an other.
- */
- jcr->acl_ctx->flags &= ~BACL_FLAG_RESTORE_NATIVE;
- Mmsg1(jcr->errmsg,
- _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
- jcr->last_fname);
- return bacl_rtn_error;
- } else if (acl_enabled < 0) {
- berrno be;
- if (errno == ENOENT) {
- return bacl_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- }
- /*
- * On a filesystem with ACL support make sure this particular ACL type can be restored.
- */
- switch (stream) {
- case STREAM_ACL_SOLARIS_POSIX:
- /*
- * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
- */
- if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
- Mmsg1(jcr->errmsg,
- _("Trying to restore POSIX acl on file \"%s\" on filesystem without aclent acl support\n"),
- jcr->last_fname);
- return bacl_rtn_error;
- }
- break;
- case STREAM_ACL_SOLARIS_NFS4:
- /*
- * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
- */
- if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
- Mmsg1(jcr->errmsg,
- _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without ace acl support\n"),
- jcr->last_fname);
- return bacl_rtn_error;
- }
- break;
- default:
- /*
- * Stream id which doesn't describe the type of acl which is encoded.
- */
- break;
- }
-
- if ((error = acl_fromtext(content, &aclp)) != 0) {
- Mmsg2(jcr->errmsg,
- _("acl_fromtext error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, acl_strerror(error));
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
-
- /*
- * Validate that the conversion gave us the correct acl type.
- */
- switch (stream) {
- case STREAM_ACL_SOLARIS_POSIX:
- if (acl_type(aclp) != ACLENT_T) {
- Mmsg1(jcr->errmsg,
- _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
- jcr->last_fname);
- return bacl_rtn_error;
- }
- break;
- case STREAM_ACL_SOLARIS_NFS4:
- if (acl_type(aclp) != ACE_T) {
- Mmsg1(jcr->errmsg,
- _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
- jcr->last_fname);
- return bacl_rtn_error;
- }
- break;
- default:
- /*
- * Stream id which doesn't describe the type of acl which is encoded.
- */
- break;
- }
-
- /*
- * Restore the ACLs, but don't complain about links which really should
- * not have attributes, and the file it is linked to may not yet be restored.
- * This is only true for the old acl streams as in the new implementation we
- * don't save acls of symlinks (which cannot have acls anyhow)
- */
- if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
- if (errno == ENOENT) {
- acl_free(aclp);
- return bacl_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, acl_strerror(error));
- Dmsg1(100, "%s", jcr->errmsg);
- acl_free(aclp);
- return bacl_rtn_error;
- }
- }
-
- acl_free(aclp);
- return bacl_rtn_ok;
-}
-
-#else /* HAVE_EXTENDED_ACL */
-
-/*
- * Define the supported ACL streams for this OS
- */
-static int os_access_acl_streams[1] = {
- STREAM_ACL_SOLARIS_POSIX
-};
-static int os_default_acl_streams[1] = {
- -1
-};
-
-/*
- * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
- * There is no need to store those acls as we already store the stat bits too.
- */
-static bool acl_is_trivial(int count, aclent_t *entries)
-{
- int n;
- aclent_t *ace;
-
- for (n = 0; n < count; n++) {
- ace = &entries[n];
-
- if (!(ace->a_type == USER_OBJ ||
- ace->a_type == GROUP_OBJ ||
- ace->a_type == OTHER_OBJ ||
- ace->a_type == CLASS_OBJ))
- return false;
- }
- return true;
-}
-
-/*
- * OS specific functions for handling different types of acl streams.
- */
-static bacl_rtn_code solaris_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- int n;
- aclent_t *acls;
- char *acl_text;
-
- n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
- if (n < MIN_ACL_ENTRIES) {
- return bacl_rtn_error;
- }
-
- acls = (aclent_t *)malloc(n * sizeof(aclent_t));
- if (acl(jcr->last_fname, GETACL, n, acls) == n) {
- if (acl_is_trivial(n, acls)) {
- /*
- * The ACLs simply reflect the (already known) standard permissions
- * So we don't send an ACL stream to the SD.
- */
- free(acls);
- pm_strcpy(jcr->acl_ctx->content, "");
- jcr->acl_ctx->content_length = 0;
- return bacl_rtn_ok;
- }
-
- if ((acl_text = acltotext(acls, n)) != NULL) {
- jcr->acl_ctx->content_length =
- pm_strcpy(jcr->acl_ctx->content, acl_text);
- actuallyfree(acl_text);
- free(acls);
- return send_acl_stream(jcr, STREAM_ACL_SOLARIS_POSIX);
- }
-
- berrno be;
- Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- }
-
- free(acls);
- return bacl_rtn_error;
-}
-
-static bacl_rtn_code solaris_restore_acl_streams(JCR *jcr, int stream, char *content,
- uint32_t content_length)
-{
- int n;
- aclent_t *acls;
-
- acls = aclfromtext(content, &n);
- if (!acls) {
- berrno be;
-
- Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
-
- /*
- * Restore the ACLs, but don't complain about links which really should
- * not have attributes, and the file it is linked to may not yet be restored.
- */
- if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
- berrno be;
- if (errno == ENOENT) {
- actuallyfree(acls);
- return bacl_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- actuallyfree(acls);
- return bacl_rtn_error;
- }
- }
- actuallyfree(acls);
- return bacl_rtn_ok;
-}
-#endif /* HAVE_EXTENDED_ACL */
-
-/*
- * For this OS setup the build and parse function pointer to the OS specific functions.
- */
-static bacl_rtn_code (*os_backup_acl_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- solaris_backup_acl_streams;
-static bacl_rtn_code (*os_restore_acl_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- solaris_restore_acl_streams;
-
-#endif /* HAVE_SUN_OS */
-#endif /* HAVE_ACL */
-
-#if defined(HAVE_AFS_ACL)
-
-#if defined(HAVE_AFS_AFSINT_H) && defined(HAVE_AFS_VENUS_H)
-#include <afs/afsint.h>
-#include <afs/venus.h>
-#else
-#error "configure failed to detect availability of afs/afsint.h and/or afs/venus.h"
-#endif
-
-/*
- * External references to functions in the libsys library function not in current include files.
- */
-extern "C" {
-long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow);
-}
-
-static bacl_rtn_code afs_backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- int error;
- struct ViceIoctl vip;
- char acl_text[BUFSIZ];
-
- /*
- * AFS ACLs can only be set on a directory, so no need to try to
- * request them for anything other then that.
- */
- if (ff_pkt->type != FT_DIREND) {
- return bacl_rtn_ok;
- }
-
- vip.in = NULL;
- vip.in_size = 0;
- vip.out = acl_text;
- vip.out_size = sizeof(acl_text);
- memset((caddr_t)acl_text, 0, sizeof(acl_text));
-
- if ((error = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0) {
- berrno be;
- Mmsg2(jcr->errmsg, _("pioctl VIOCGETAL error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- jcr->acl_ctx->content_length = pm_strcpy(jcr->acl_ctx->content, acl_text);
- return send_acl_stream(jcr, STREAM_ACL_AFS_TEXT);
-}
-
-static bacl_rtn_code afs_restore_acl_stream(JCR *jcr, int stream, char *content,
- uint32_t content_length)
-{
- int error;
- struct ViceIoctl vip;
-
- vip.in = content;
- vip.in_size = content_length;
- vip.out = NULL;
- vip.out_size = 0;
-
- if ((error = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0) {
- berrno be;
- Mmsg2(jcr->errmsg, _("pioctl VIOCSETAL error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- return bacl_rtn_ok;
-}
-#endif /* HAVE_AFS_ACL */
-
-/*
- * Entry points when compiled with support for ACLs on a supported platform.
- */
-
-/*
- * Read and send an ACL for the last encountered file.
- */
-bool backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- bacl_rtn_code rtn = bacl_rtn_error;
-
- if (!(ff_pkt->flags & FO_ACL && ff_pkt->type != FT_LNK && !ff_pkt->cmd_plugin)) {
- return true; /* No acl request */
- }
- jcr->errmsg[0] = 0;
-
- /*
- * See if we are changing from one device to an other.
- * We save the current device we are scanning and compare
- * it with the current st_dev in the last stat performed on
- * the file we are currently storing.
- */
- if (jcr->acl_ctx->current_dev != ff_pkt->statp.st_dev) {
- /*
- * Reset the acl save flags.
- */
- jcr->acl_ctx->flags = 0;
-
-#if defined(HAVE_AFS_ACL)
- /*
- * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
- * Set the BACL_FLAG_SAVE_AFS flag if it is. If not set the BACL_FLAG_SAVE_NATIVE flag.
- */
- if (fstype_cmp(ff_pkt, "afs")) {
- jcr->acl_ctx->flags |= BACL_FLAG_SAVE_AFS;
- } else {
- jcr->acl_ctx->flags |= BACL_FLAG_SAVE_NATIVE;
- }
-#else
- jcr->acl_ctx->flags |= BACL_FLAG_SAVE_NATIVE;
-#endif
-
- /*
- * Save that we started scanning a new filesystem.
- */
- jcr->acl_ctx->current_dev = ff_pkt->statp.st_dev;
- }
-
-#ifdef HAVE_AFS_ACL
- /*
- * See if the BACL_FLAG_SAVE_AFS flag is set which lets us know if we should
- * save AFS ACLs.
- */
- if (jcr->acl_ctx->flags & BACL_FLAG_SAVE_AFS) {
- rtn = afs_backup_acl_streams(jcr, ff_pkt);
- goto get_out;
- }
-#endif
-
-#ifdef HAVE_ACL
- /*
- * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should
- * save native ACLs.
- */
- if (jcr->acl_ctx->flags & BACL_FLAG_SAVE_NATIVE) {
- /*
- * Call the appropriate function.
- */
- if (os_backup_acl_streams) {
- rtn = os_backup_acl_streams(jcr, ff_pkt);
- goto get_out;
- }
- } else {
- return true;
- }
-#endif
-
-get_out:
- switch (rtn) {
- case bacl_rtn_fatal:
- return false;
- case bacl_rtn_ok:
- return true;
- case bacl_rtn_error:
- if (jcr->acl_ctx->nr_errors < ACL_MAX_ERROR_PRINT_PER_JOB) {
- if (jcr->errmsg[0]) {
- Jmsg(jcr, M_WARNING, 0, "Operating system ACLs not configured.\n");
- } else {
- Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
- }
- jcr->acl_ctx->nr_errors++;
- }
- return true;
- }
- /* Theoretically we cannot get here */
- return false;
-}
-
-bacl_rtn_code restore_acl_streams(JCR *jcr, int stream,
- char *content, uint32_t content_length)
-{
- int ret;
- struct stat st;
- unsigned int cnt;
-
- /*
- * See if we are changing from one device to an other.
- * We save the current device we are restoring to and compare
- * it with the current st_dev in the last stat performed on
- * the file we are currently restoring.
- */
- ret = lstat(jcr->last_fname, &st);
- if (ret < 0) {
- berrno be;
- if (errno == ENOENT) {
- return bacl_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("Unable to stat file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bacl_rtn_error;
- }
- }
- if (jcr->acl_ctx->current_dev != st.st_dev) {
- /*
- * Reset the acl save flags.
- */
- jcr->acl_ctx->flags = 0;
-
-#if defined(HAVE_AFS_ACL)
- /*
- * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem
- * Set the BACL_FLAG_RESTORE_AFS flag if it is. If not set the BACL_FLAG_RETORE_NATIVE flag.
- */
- if (fstype_cmp(ff_pkt, "afs")) {
- jcr->acl_ctx->flags |= BACL_FLAG_RESTORE_AFS;
- } else {
- jcr->acl_ctx->flags |= BACL_FLAG_RESTORE_NATIVE;
- }
-#else
- jcr->acl_ctx->flags |= BACL_FLAG_RESTORE_NATIVE;
-#endif
-
- /* Save that we started restoring to a new filesystem. */
- jcr->acl_ctx->current_dev = st.st_dev;
- }
-
- switch (stream) {
-#ifdef HAVE_AFS_ACL
- case STREAM_ACL_AFS_TEXT:
- if (jcr->acl_ctx->flags & BACL_FLAG_RESTORE_AFS) {
- return afs_restore_acl_stream(jcr, stream, content, content_length);
- } else {
- /*
- * Increment error count but don't log an error again for the same filesystem.
- */
- jcr->acl_ctx->nr_errors++;
- return bacl_rtn_ok;
- }
-#endif
-
-#ifdef HAVE_ACL
- case STREAM_UNIX_ACCESS_ACL:
- case STREAM_UNIX_DEFAULT_ACL:
- /*
- * Handle legacy ACL streams.
- */
- if ((jcr->acl_ctx->flags & BACL_FLAG_RESTORE_NATIVE) && os_restore_acl_streams) {
- return os_restore_acl_streams(jcr, stream, content, content_length);
- } else {
- /*
- * Increment error count but don't log an error again for the same filesystem.
- */
- jcr->acl_ctx->nr_errors++;
- return bacl_rtn_ok;
- }
- break;
- default:
- if ((jcr->acl_ctx->flags & BACL_FLAG_RESTORE_NATIVE) && os_restore_acl_streams) {
- /*
- * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
- */
- for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
- if (os_access_acl_streams[cnt] == stream) {
- return os_restore_acl_streams(jcr, stream, content, content_length);
- }
- }
- /*
- * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
- */
- for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
- if (os_default_acl_streams[cnt] == stream) {
- return os_restore_acl_streams(jcr, stream, content, content_length);
- }
- }
- } else {
- /*
- * Increment error count but don't log an error again for the same filesystem.
- */
- jcr->acl_ctx->nr_errors++;
- return bacl_rtn_ok;
- }
- break;
-#else
- default:
- break;
-#endif
- }
- Qmsg2(jcr, M_WARNING, 0, _("Cannot restore ACLs of %s - incompatible acl stream encountered - %d\n"),
- jcr->last_fname, stream);
- return bacl_rtn_error;
-}
-#endif
+++ /dev/null
-/*
- Bacula(R) - The Network Backup Solution
-
- Copyright (C) 2000-2015 Kern Sibbald
- Copyright (C) 2004-2014 Free Software Foundation Europe e.V.
-
- The original author of Bacula is Kern Sibbald, with contributions
- from many others, a complete list can be found in the file AUTHORS.
-
- You may use this file and others of this release according to the
- license defined in the LICENSE file, which includes the Affero General
- Public License, v3.0 ("AGPLv3") and some additional permissions and
- terms pursuant to its AGPLv3 Section 7.
-
- This notice must be preserved when any source code is
- conveyed and/or propagated.
-
- Bacula(R) is a registered trademark of Kern Sibbald.
-*/
-/*
- * Properties we use for getting and setting ACLs.
- */
-
-#ifndef __BACL_H_
-#define __BACL_H_
-
-/* Global JCR data */
-struct acl_ctx_t {
- uint32_t nr_errors;
- uint32_t flags; /* See BACL_FLAG_* */
- uint32_t current_dev;
- uint32_t content_length;
- POOLMEM *content;
-};
-
-/*
- * We support the following types of ACLs
- */
-typedef enum {
- BACL_TYPE_NONE = 0,
- BACL_TYPE_ACCESS = 1,
- BACL_TYPE_DEFAULT = 2,
- BACL_TYPE_DEFAULT_DIR = 3,
- BACL_TYPE_EXTENDED = 4,
- BACL_TYPE_NFS4 = 5
-} bacl_type;
-
-#define BACL_FLAG_SAVE_NATIVE 0x01
-#define BACL_FLAG_SAVE_AFS 0x02
-#define BACL_FLAG_RESTORE_NATIVE 0x04
-#define BACL_FLAG_RESTORE_AFS 0x08
-
-/*
- * Ensure we have none
- */
-#ifndef ACL_TYPE_NONE
-#define ACL_TYPE_NONE 0x0
-#endif
-
-#ifdef HAVE_IRIX_OS
-#define BACL_ENOTSUP ENOSYS
-#else
-#define BACL_ENOTSUP EOPNOTSUPP
-#endif /* HAVE_IRIX_OS */
-
-#endif /* __BACL_H_ */
/*
Bacula(R) - The Network Backup Solution
- Copyright (C) 2000-2015 Kern Sibbald
+ Copyright (C) 2000-2016 Kern Sibbald
The original author of Bacula is Kern Sibbald, with contributions
from many others, a complete list can be found in the file AUTHORS.
Public License, v3.0 ("AGPLv3") and some additional permissions and
terms pursuant to its AGPLv3 Section 7.
- This notice must be preserved when any source code is
+ This notice must be preserved when any source code is
conveyed and/or propagated.
Bacula(R) is a registered trademark of Kern Sibbald.
*/
/*
- * Bacula File Daemon backup.c send file attributes and data
+ * Bacula File Daemon backup.c send file attributes and data
* to the Storage daemon.
*
* Kern Sibbald, March MM
#include "bacula.h"
#include "filed.h"
#include "backup.h"
-
+
#ifdef HAVE_LZO
const bool have_lzo = true;
-#else
+#else
const bool have_lzo = false;
-#endif
-
+#endif
+
#ifdef HAVE_LIBZ
const bool have_libz = true;
-#else
+#else
const bool have_libz = false;
-#endif
-
+#endif
+
/* Forward referenced functions */
int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level);
static int send_data(bctx_t &bctx, int stream);
if (client) {
buf_size = client->max_network_buffer_size;
} else {
- buf_size = 0; /* use default */
+ buf_size = 0; /* use default */
}
if (!sd->set_buffer_size(buf_size, BNET_SETBUF_WRITE)) {
jcr->setJobStatus(JS_ErrorTerminated);
* same output buffer can be used without growing it.
*
* For LZO1X compression the recommended value is :
- * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3 + sizeof(comp_stream_header)
+ * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3 + sizeof(comp_stream_header)
*
* The zlib compression workset is initialized here to minimize
* the "per file" load. The jcr member is only set, if the init
pZlibStream->state = Z_NULL;
if (deflateInit(pZlibStream, Z_DEFAULT_COMPRESSION) == Z_OK) {
- jcr->pZLIB_compress_workset = pZlibStream;
+ jcr->pZLIB_compress_workset = pZlibStream;
} else {
- free (pZlibStream);
+ free (pZlibStream);
}
}
#endif
lzo_voidp pLzoMem = (lzo_voidp) malloc(LZO1X_1_MEM_COMPRESS);
if (pLzoMem) {
if (lzo_init() == LZO_E_OK) {
- jcr->LZO_compress_workset = pLzoMem;
+ jcr->LZO_compress_workset = pLzoMem;
} else {
- free (pLzoMem);
+ free (pLzoMem);
}
}
#endif
}
start_heartbeat_monitor(jcr);
-#ifdef HAVE_ACL
- jcr->acl_ctx = (acl_ctx_t *)malloc(sizeof(acl_ctx_t));
- memset(jcr->acl_ctx, 0, sizeof(acl_ctx_t));
- jcr->acl_ctx->content = get_pool_memory(PM_MESSAGE);
-#endif
-#ifdef HAVE_XATTR
- jcr->xattr_ctx = (xattr_ctx_t *)malloc(sizeof(xattr_ctx_t));
- memset(jcr->xattr_ctx, 0, sizeof(xattr_ctx_t));
- jcr->xattr_ctx->content = get_pool_memory(PM_MESSAGE);
-#endif
-
+ jcr->xacl = (XACL*)new_xacl();
+
/* Subroutine save_file() is called for each file */
if (!find_files(jcr, (FF_PKT *)jcr->ff, save_file, plugin_save)) {
- ok = false; /* error */
+ ok = false; /* error */
jcr->setJobStatus(JS_ErrorTerminated);
}
-#ifdef HAVE_ACL
- if (jcr->acl_ctx->nr_errors > 0) {
- Jmsg(jcr, M_WARNING, 0, _("Had %ld acl errors while doing backup\n"),
- jcr->acl_ctx->nr_errors);
- }
-#endif
-#ifdef HAVE_XATTR
- if (jcr->xattr_ctx->nr_errors > 0) {
- Jmsg(jcr, M_WARNING, 0, _("Had %ld xattr errors while doing backup\n"),
- jcr->xattr_ctx->nr_errors);
- }
-#endif
+ if (jcr->xacl->get_acl_nr_errors() > 0) {
+ Jmsg(jcr, M_WARNING, 0, _("Had %ld acl errors while doing backup\n"), jcr->xacl->get_acl_nr_errors());
+ }
+
+ if (jcr->xacl->get_xattr_nr_errors() > 0) {
+ Jmsg(jcr, M_WARNING, 0, _("Had %ld xattr errors while doing backup\n"), jcr->xacl->get_xattr_nr_errors());
+ }
+
/* Delete or keep snapshots */
close_snapshot_backup_session(jcr);
close_vss_backup_session(jcr);
- accurate_finish(jcr); /* send deleted or base file list to SD */
+ accurate_finish(jcr); /* send deleted or base file list to SD */
stop_heartbeat_monitor(jcr);
- sd->signal(BNET_EOD); /* end of sending data */
+ sd->signal(BNET_EOD); /* end of sending data */
-
-#ifdef HAVE_ACL
- if (jcr->acl_ctx) {
- free_and_null_pool_memory(jcr->acl_ctx->content);
- bfree_and_null(jcr->acl_ctx);
- }
-#endif
-#ifdef HAVE_XATTR
- if (jcr->xattr_ctx) {
- free_and_null_pool_memory(jcr->xattr_ctx->content);
- bfree_and_null(jcr->xattr_ctx);
- }
-#endif
+ if (jcr->xacl) {
+ delete(jcr->xacl);
+ jcr->xacl = NULL;
+ }
if (jcr->big_buf) {
bfree_and_null(jcr->big_buf);
}
* Send the file and its data to the Storage daemon.
*
* Returns: 1 if OK
- * 0 if error
- * -1 to ignore file/directory (not used here)
+ * 0 if error
+ * -1 to ignore file/directory (not used here)
*/
int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
{
int stat;
int rtnstat = 0;
bool has_file_data = false;
- struct save_pkt sp; /* used by option plugin */
+ struct save_pkt sp; /* used by option plugin */
BSOCK *sd = jcr->store_bsock;
- bctx_t bctx; /* backup context */
+ bctx_t bctx; /* backup context */
memset(&bctx, 0, sizeof(bctx));
bctx.sd = sd;
time_t now = time(NULL);
if (jcr->last_stat_time == 0) {
jcr->last_stat_time = now;
- jcr->stat_interval = 30; /* Default 30 seconds */
+ jcr->stat_interval = 30; /* Default 30 seconds */
} else if (now >= jcr->last_stat_time + jcr->stat_interval) {
jcr->dir_bsock->fsend("Progress Job=x files=%ld bytes=%lld bps=%ld\n",
- jcr->JobFiles, jcr->JobBytes, jcr->LastRate);
+ jcr->JobFiles, jcr->JobBytes, jcr->LastRate);
jcr->last_stat_time = now;
}
return 0;
}
- jcr->num_files_examined++; /* bump total file count */
+ jcr->num_files_examined++; /* bump total file count */
switch (ff_pkt->type) {
- case FT_LNKSAVED: /* Hard linked, file already saved */
+ case FT_LNKSAVED: /* Hard linked, file already saved */
Dmsg2(130, "FT_LNKSAVED hard link: %s => %s\n", ff_pkt->fname, ff_pkt->link);
break;
case FT_REGE:
break;
case FT_DIRBEGIN:
jcr->num_files_examined--; /* correct file count */
- return 1; /* not used */
+ return 1; /* not used */
case FT_NORECURSE:
- Jmsg(jcr, M_INFO, 1, _(" Recursion turned off. Will not descend from %s into %s\n"),
- ff_pkt->top_fname, ff_pkt->fname);
+ Jmsg(jcr, M_INFO, 1, _(" Recursion turned off. Will not descend from %s into %s\n"),
+ ff_pkt->top_fname, ff_pkt->fname);
ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
break;
case FT_NOFSCHG:
/* Suppress message for /dev filesystems */
if (!is_in_fileset(ff_pkt)) {
- Jmsg(jcr, M_INFO, 1, _(" %s is a different filesystem. Will not descend from %s into it.\n"),
- ff_pkt->fname, ff_pkt->top_fname);
+ Jmsg(jcr, M_INFO, 1, _(" %s is a different filesystem. Will not descend from %s into it.\n"),
+ ff_pkt->fname, ff_pkt->top_fname);
}
ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
break;
case FT_INVALIDFS:
- Jmsg(jcr, M_INFO, 1, _(" Disallowed filesystem. Will not descend from %s into %s\n"),
- ff_pkt->top_fname, ff_pkt->fname);
+ Jmsg(jcr, M_INFO, 1, _(" Disallowed filesystem. Will not descend from %s into %s\n"),
+ ff_pkt->top_fname, ff_pkt->fname);
ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
break;
case FT_INVALIDDT:
- Jmsg(jcr, M_INFO, 1, _(" Disallowed drive type. Will not descend into %s\n"),
- ff_pkt->fname);
+ Jmsg(jcr, M_INFO, 1, _(" Disallowed drive type. Will not descend into %s\n"),
+ ff_pkt->fname);
break;
case FT_REPARSE:
case FT_JUNCTION:
case FT_SPEC:
Dmsg1(130, "FT_SPEC saving: %s\n", ff_pkt->fname);
if (S_ISSOCK(ff_pkt->statp.st_mode)) {
- Jmsg(jcr, M_SKIPPED, 1, _(" Socket file skipped: %s\n"), ff_pkt->fname);
- return 1;
+ Jmsg(jcr, M_SKIPPED, 1, _(" Socket file skipped: %s\n"), ff_pkt->fname);
+ return 1;
}
break;
case FT_RAW:
case FT_NOACCESS: {
berrno be;
Jmsg(jcr, M_NOTSAVED, 0, _(" Could not access \"%s\": ERR=%s\n"), ff_pkt->fname,
- be.bstrerror(ff_pkt->ff_errno));
+ be.bstrerror(ff_pkt->ff_errno));
jcr->JobErrors++;
return 1;
}
case FT_NOFOLLOW: {
berrno be;
Jmsg(jcr, M_NOTSAVED, 0, _(" Could not follow link \"%s\": ERR=%s\n"),
- ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
+ ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
jcr->JobErrors++;
return 1;
}
case FT_NOSTAT: {
berrno be;
Jmsg(jcr, M_NOTSAVED, 0, _(" Could not stat \"%s\": ERR=%s\n"), ff_pkt->fname,
- be.bstrerror(ff_pkt->ff_errno));
+ be.bstrerror(ff_pkt->ff_errno));
jcr->JobErrors++;
return 1;
}
case FT_NOOPEN: {
berrno be;
Jmsg(jcr, M_NOTSAVED, 0, _(" Could not open directory \"%s\": ERR=%s\n"),
- ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
+ ff_pkt->fname, be.bstrerror(ff_pkt->ff_errno));
jcr->JobErrors++;
return 1;
}
Dmsg1(130, "FT_DELETED: %s\n", ff_pkt->fname);
break;
default:
- Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d; not saved: %s\n"),
- ff_pkt->type, ff_pkt->fname);
+ Jmsg(jcr, M_NOTSAVED, 0, _(" Unknown file type %d; not saved: %s\n"),
+ ff_pkt->type, ff_pkt->fname);
jcr->JobErrors++;
return 1;
}
/* ask the option plugin what to do with this file */
switch (plugin_option_handle_file(jcr, ff_pkt, &sp)) {
case bRC_OK:
- Dmsg2(10, "Option plugin %s will be used to backup %s\n",
- ff_pkt->plugin, ff_pkt->fname);
- do_plugin_set = true;
- break;
+ Dmsg2(10, "Option plugin %s will be used to backup %s\n",
+ ff_pkt->plugin, ff_pkt->fname);
+ do_plugin_set = true;
+ break;
case bRC_Skip:
- Dmsg2(10, "Option plugin %s decided to skip %s\n",
- ff_pkt->plugin, ff_pkt->fname);
- goto good_rtn;
+ Dmsg2(10, "Option plugin %s decided to skip %s\n",
+ ff_pkt->plugin, ff_pkt->fname);
+ goto good_rtn;
default:
- Dmsg2(10, "Option plugin %s decided to let bacula handle %s\n",
- ff_pkt->plugin, ff_pkt->fname);
- break;
+ Dmsg2(10, "Option plugin %s decided to let bacula handle %s\n",
+ ff_pkt->plugin, ff_pkt->fname);
+ break;
}
}
if (do_plugin_set) {
/* Tell bfile that it needs to call plugin */
if (!set_cmd_plugin(&ff_pkt->bfd, jcr)) {
- goto bail_out;
+ goto bail_out;
}
- send_plugin_name(jcr, sd, true); /* signal start of plugin data */
+ send_plugin_name(jcr, sd, true); /* signal start of plugin data */
plugin_started = true;
}
/** Set up the encryption context and send the session data to the SD */
if (has_file_data && jcr->crypto.pki_encrypt) {
if (!crypto_session_send(jcr, sd)) {
- goto bail_out;
+ goto bail_out;
}
}
do_read = ff_pkt->statp.st_size > 0;
#endif
} else if (ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO ||
- ff_pkt->type == FT_REPARSE || ff_pkt->type == FT_JUNCTION ||
- (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) {
+ ff_pkt->type == FT_REPARSE || ff_pkt->type == FT_JUNCTION ||
+ (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) {
do_read = true;
}
btimer_t *tid;
if (ff_pkt->type == FT_FIFO) {
- tid = start_thread_timer(jcr, pthread_self(), 60);
+ tid = start_thread_timer(jcr, pthread_self(), 60);
} else {
- tid = NULL;
+ tid = NULL;
}
int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
ff_pkt->bfd.reparse_point = (ff_pkt->type == FT_REPARSE ||
- ff_pkt->type == FT_JUNCTION);
+ ff_pkt->type == FT_JUNCTION);
set_fattrs(&ff_pkt->bfd, &ff_pkt->statp);
if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0) < 0) {
- ff_pkt->ff_errno = errno;
- berrno be;
- Jmsg(jcr, M_NOTSAVED, 0, _(" Cannot open \"%s\": ERR=%s.\n"), ff_pkt->fname,
- be.bstrerror());
- jcr->JobErrors++;
- if (tid) {
- stop_thread_timer(tid);
- tid = NULL;
- }
- goto good_rtn;
+ ff_pkt->ff_errno = errno;
+ berrno be;
+ Jmsg(jcr, M_NOTSAVED, 0, _(" Cannot open \"%s\": ERR=%s.\n"), ff_pkt->fname,
+ be.bstrerror());
+ jcr->JobErrors++;
+ if (tid) {
+ stop_thread_timer(tid);
+ tid = NULL;
+ }
+ goto good_rtn;
}
if (tid) {
- stop_thread_timer(tid);
- tid = NULL;
+ stop_thread_timer(tid);
+ tid = NULL;
}
stat = send_data(bctx, bctx.data_stream);
if (ff_pkt->flags & FO_CHKCHANGES) {
- has_file_changed(jcr, ff_pkt);
+ has_file_changed(jcr, ff_pkt);
}
bclose(&ff_pkt->bfd);
if (!stat) {
- goto bail_out;
+ goto bail_out;
}
}
#endif
/*
- * Save ACLs when requested and available for anything not being a symlink
- * and not being a plugin.
- */
-#ifdef HAVE_ACL
- if (!backup_acl_streams(jcr, ff_pkt)) {
- goto bail_out;
- }
-#endif
-
- /*
- * Save Extended Attributes when requested and available for all files not
- * being a plugin.
+ * Save ACLs and Extended Attributes when requested and available
+ * for anything not being a symlink and not being a plugin (why not?).
*/
-#ifdef HAVE_XATTR
- if (!backup_xattr_streams(jcr, ff_pkt)) {
- goto bail_out;
+ if (jcr->xacl){
+ if (jcr->xacl->backup_acl(jcr, ff_pkt) == bRC_XACL_error) {
+ goto bail_out;
+ }
+ if (jcr->xacl->backup_xattr(jcr, ff_pkt) == bRC_XACL_error) {
+ goto bail_out;
+ }
}
-#endif
if (!crypto_terminate_digests(bctx)) {
goto bail_out;
send_plugin_name(jcr, sd, false); /* signal end of plugin data */
}
if (ff_pkt->opt_plugin) {
- jcr->plugin_sp = NULL; /* sp is local to this function */
+ jcr->plugin_sp = NULL; /* sp is local to this function */
jcr->plugin_ctx = NULL;
jcr->plugin = NULL;
jcr->opt_plugin = false;
bctx.fileAddr = 0;
bctx.cipher_ctx = NULL;
bctx.msgsave = sd->msg;
- bctx.rbuf = sd->msg; /* read buffer */
- bctx.wbuf = sd->msg; /* write buffer */
- bctx.cipher_input = (uint8_t *)bctx.rbuf; /* encrypt uncompressed data */
+ bctx.rbuf = sd->msg; /* read buffer */
+ bctx.wbuf = sd->msg; /* write buffer */
+ bctx.cipher_input = (uint8_t *)bctx.rbuf; /* encrypt uncompressed data */
Dmsg1(300, "Saving data, type=%d\n", bctx.ff_pkt->type);
/**
* Send Data header to Storage daemon
- * <file-index> <stream> <expected stream length>
+ * <file-index> <stream> <expected stream length>
*/
if (!sd->fsend("%ld %d %lld", jcr->JobFiles, stream,
- (int64_t)bctx.ff_pkt->statp.st_size)) {
+ (int64_t)bctx.ff_pkt->statp.st_size)) {
if (!jcr->is_job_canceled()) {
- Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
- sd->bstrerror());
+ Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
+ sd->bstrerror());
}
goto err;
}
/**
* Make space at beginning of buffer for fileAddr because this
- * same buffer will be used for writing if compression is off.
+ * same buffer will be used for writing if compression is off.
*/
if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
bctx.rbuf += OFFSET_FADDR_SIZE;
Dmsg1(200, "Fattrs=0X%x\n", bctx.ff_pkt->bfd.fattrs);
if (bctx.ff_pkt->bfd.fattrs & FILE_ATTRIBUTE_ENCRYPTED) {
if (!p_ReadEncryptedFileRaw) {
- Jmsg0(bctx.jcr, M_FATAL, 0, _("Windows Encrypted data not supported on this OS.\n"));
- goto err;
+ Jmsg0(bctx.jcr, M_FATAL, 0, _("Windows Encrypted data not supported on this OS.\n"));
+ goto err;
}
/* This single call reads all EFS data delivers it to a callback */
if (p_ReadEncryptedFileRaw((PFE_EXPORT_FUNC)read_efs_data_cb, &bctx,
- bctx.ff_pkt->bfd.pvContext) != 0) {
- goto err;
+ bctx.ff_pkt->bfd.pvContext) != 0) {
+ goto err;
}
/* All read, so skip to finish sending */
goto finish_sending;
*/
while ((sd->msglen=(uint32_t)bread(&bctx.ff_pkt->bfd, bctx.rbuf, bctx.rsize)) > 0) {
if (!process_and_send_data(bctx)) {
- goto err;
+ goto err;
}
} /* end while read file data */
goto finish_sending;
finish_sending:
- if (sd->msglen < 0) { /* error */
+ if (sd->msglen < 0) { /* error */
berrno be;
Jmsg(jcr, M_ERROR, 0, _("Read error on file %s. ERR=%s\n"),
- bctx.ff_pkt->fname, be.bstrerror(bctx.ff_pkt->bfd.berrno));
- if (jcr->JobErrors++ > 1000) { /* insanity check */
- Jmsg(jcr, M_FATAL, 0, _("Too many errors. JobErrors=%d.\n"), jcr->JobErrors);
+ bctx.ff_pkt->fname, be.bstrerror(bctx.ff_pkt->bfd.berrno));
+ if (jcr->JobErrors++ > 1000) { /* insanity check */
+ Jmsg(jcr, M_FATAL, 0, _("Too many errors. JobErrors=%d.\n"), jcr->JobErrors);
}
} else if (bctx.ff_pkt->flags & FO_ENCRYPT) {
/**
* buffered data.
*/
if (!crypto_cipher_finalize(bctx.cipher_ctx, (uint8_t *)jcr->crypto.crypto_buf,
- &bctx.encrypted_len)) {
- /* Padding failed. Shouldn't happen. */
- Jmsg(jcr, M_FATAL, 0, _("Encryption padding error\n"));
- goto err;
+ &bctx.encrypted_len)) {
+ /* Padding failed. Shouldn't happen. */
+ Jmsg(jcr, M_FATAL, 0, _("Encryption padding error\n"));
+ goto err;
}
/** Note, on SSL pre-0.9.7, there is always some output */
if (bctx.encrypted_len > 0) {
- sd->msglen = bctx.encrypted_len; /* set encrypted length */
- sd->msg = jcr->crypto.crypto_buf; /* set correct write buffer */
- if (!sd->send()) {
- if (!jcr->is_job_canceled()) {
- Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
- sd->bstrerror());
- }
- goto err;
- }
- Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
- jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed/encrypted */
- sd->msg = bctx.msgsave; /* restore bnet buffer */
+ sd->msglen = bctx.encrypted_len; /* set encrypted length */
+ sd->msg = jcr->crypto.crypto_buf; /* set correct write buffer */
+ if (!sd->send()) {
+ if (!jcr->is_job_canceled()) {
+ Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
+ sd->bstrerror());
+ }
+ goto err;
+ }
+ Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
+ jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed/encrypted */
+ sd->msg = bctx.msgsave; /* restore bnet buffer */
}
}
if (!sd->signal(BNET_EOD)) { /* indicate end of file data */
if (!jcr->is_job_canceled()) {
- Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
- sd->bstrerror());
+ Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
+ sd->bstrerror());
}
goto err;
}
ser_declare;
bool allZeros = false;
if ((sd->msglen == bctx.rsize &&
- bctx.fileAddr+sd->msglen < (uint64_t)bctx.ff_pkt->statp.st_size) ||
- ((bctx.ff_pkt->type == FT_RAW || bctx.ff_pkt->type == FT_FIFO) &&
- (uint64_t)bctx.ff_pkt->statp.st_size == 0)) {
- allZeros = is_buf_zero(bctx.rbuf, bctx.rsize);
+ bctx.fileAddr+sd->msglen < (uint64_t)bctx.ff_pkt->statp.st_size) ||
+ ((bctx.ff_pkt->type == FT_RAW || bctx.ff_pkt->type == FT_FIFO) &&
+ (uint64_t)bctx.ff_pkt->statp.st_size == 0)) {
+ allZeros = is_buf_zero(bctx.rbuf, bctx.rsize);
}
if (!allZeros) {
- /** Put file address as first data in buffer */
- ser_begin(bctx.wbuf, OFFSET_FADDR_SIZE);
- ser_uint64(bctx.fileAddr); /* store fileAddr in begin of buffer */
+ /** Put file address as first data in buffer */
+ ser_begin(bctx.wbuf, OFFSET_FADDR_SIZE);
+ ser_uint64(bctx.fileAddr); /* store fileAddr in begin of buffer */
}
- bctx.fileAddr += sd->msglen; /* update file address */
+ bctx.fileAddr += sd->msglen; /* update file address */
/** Skip block of all zeros */
if (allZeros) {
- return true; /* skip block of zeros */
+ return true; /* skip block of zeros */
}
} else if (bctx.ff_pkt->flags & FO_OFFSETS) {
ser_declare;
ser_uint64(bctx.ff_pkt->bfd.offset); /* store offset in begin of buffer */
}
- jcr->ReadBytes += sd->msglen; /* count bytes read */
+ jcr->ReadBytes += sd->msglen; /* count bytes read */
/** Uncompressed cipher input length */
bctx.cipher_input_len = sd->msglen;
ser_declare;
if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
- bctx.cipher_input_len += OFFSET_FADDR_SIZE;
+ bctx.cipher_input_len += OFFSET_FADDR_SIZE;
}
/** Encrypt the length of the input block */
Dmsg1(20, "Encrypt len=%d\n", bctx.cipher_input_len);
if (!crypto_cipher_update(bctx.cipher_ctx, packet_len, sizeof(packet_len),
- (uint8_t *)jcr->crypto.crypto_buf, &initial_len)) {
- /** Encryption failed. Shouldn't happen. */
- Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
- goto err;
+ (uint8_t *)jcr->crypto.crypto_buf, &initial_len)) {
+ /** Encryption failed. Shouldn't happen. */
+ Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
+ goto err;
}
/** Encrypt the input block */
if (crypto_cipher_update(bctx.cipher_ctx, bctx.cipher_input, bctx.cipher_input_len,
- (uint8_t *)&jcr->crypto.crypto_buf[initial_len], &bctx.encrypted_len)) {
- if ((initial_len + bctx.encrypted_len) == 0) {
- /** No full block of data available, read more data */
- return true;
- }
- Dmsg2(400, "encrypted len=%d unencrypted len=%d\n", bctx.encrypted_len,
- sd->msglen);
- sd->msglen = initial_len + bctx.encrypted_len; /* set encrypted length */
+ (uint8_t *)&jcr->crypto.crypto_buf[initial_len], &bctx.encrypted_len)) {
+ if ((initial_len + bctx.encrypted_len) == 0) {
+ /** No full block of data available, read more data */
+ return true;
+ }
+ Dmsg2(400, "encrypted len=%d unencrypted len=%d\n", bctx.encrypted_len,
+ sd->msglen);
+ sd->msglen = initial_len + bctx.encrypted_len; /* set encrypted length */
} else {
- /** Encryption failed. Shouldn't happen. */
- Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
- goto err;
+ /** Encryption failed. Shouldn't happen. */
+ Jmsg(jcr, M_FATAL, 0, _("Encryption error\n"));
+ goto err;
}
}
if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
sd->msglen += OFFSET_FADDR_SIZE; /* include fileAddr in size */
}
- sd->msg = bctx.wbuf; /* set correct write buffer */
+ sd->msg = bctx.wbuf; /* set correct write buffer */
if (!sd->send()) {
if (!jcr->is_job_canceled()) {
- Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
- sd->bstrerror());
+ Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
+ sd->bstrerror());
}
goto err;
}
Dmsg1(130, "Send data to SD len=%d\n", sd->msglen);
- /* #endif */
+ /* #endif */
jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed/encrypted */
- sd->msg = bctx.msgsave; /* restore read buffer */
+ sd->msg = bctx.msgsave; /* restore read buffer */
return true;
err:
Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx);
jcr->lock();
- jcr->JobFiles++; /* increment number of files sent */
+ jcr->JobFiles++; /* increment number of files sent */
ff_pkt->FileIndex = jcr->JobFiles; /* return FileIndex */
pm_strcpy(jcr->last_fname, ff_pkt->fname);
jcr->unlock();
/**
* Send Attributes header to Storage daemon
- * <file-index> <stream> <info>
+ * <file-index> <stream> <info>
*/
if (!sd->fsend("%ld %d 0", jcr->JobFiles, attr_stream)) {
if (!jcr->is_canceled() && !jcr->is_incomplete()) {
- Jmsg2(jcr, M_FATAL, 0, _("Network send error to SD. Data=%s ERR=%s\n"),
- sd->msg, sd->bstrerror());
+ Jmsg2(jcr, M_FATAL, 0, _("Network send error to SD. Data=%s ERR=%s\n"),
+ sd->msg, sd->bstrerror());
}
return false;
}
/**
* Send file attributes to Storage daemon
- * File_index
- * File type
- * Filename (full path)
- * Encoded attributes
- * Link name (if type==FT_LNK or FT_LNKSAVED)
- * Encoded extended-attributes (for Win32)
+ * File_index
+ * File type
+ * Filename (full path)
+ * Encoded attributes
+ * Link name (if type==FT_LNK or FT_LNKSAVED)
+ * Encoded extended-attributes (for Win32)
*
* or send Restore Object to Storage daemon
- * File_index
- * File_type
- * Object_index
- * Object_len (possibly compressed)
- * Object_full_len (not compressed)
- * Object_compression
- * Plugin_name
- * Object_name
- * Binary Object data
+ * File_index
+ * File_type
+ * Object_index
+ * Object_len (possibly compressed)
+ * Object_full_len (not compressed)
+ * Object_compression
+ * Plugin_name
+ * Object_name
+ * Binary Object data
*
* For a directory, link is the same as fname, but with trailing
* slash. For a linked file, link is the link.
case FT_LNKSAVED:
Dmsg3(300, "Link %d %s to %s\n", jcr->JobFiles, ff_pkt->fname, ff_pkt->link);
stat = sd->fsend("%ld %d %s%c%s%c%s%c%s%c%u%c", jcr->JobFiles,
- ff_pkt->type, ff_pkt->fname, 0, attribs, 0,
- ff_pkt->link, 0, attribsEx, 0, ff_pkt->delta_seq, 0);
+ ff_pkt->type, ff_pkt->fname, 0, attribs, 0,
+ ff_pkt->link, 0, attribsEx, 0, ff_pkt->delta_seq, 0);
break;
case FT_DIREND:
case FT_REPARSE:
case FT_JUNCTION:
/* Here link is the canonical filename (i.e. with trailing slash) */
stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
- ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0,
- attribsEx, 0, ff_pkt->delta_seq, 0);
+ ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0,
+ attribsEx, 0, ff_pkt->delta_seq, 0);
break;
case FT_PLUGIN_CONFIG:
case FT_RESTORE_FIRST:
comp_len = ff_pkt->object_len;
ff_pkt->object_compression = 0;
if (ff_pkt->object_len > 1000) {
- /* Big object, compress it */
- comp_len = ff_pkt->object_len + 1000;
- POOLMEM *comp_obj = get_memory(comp_len);
- /* *** FIXME *** check Zdeflate error */
- Zdeflate(ff_pkt->object, ff_pkt->object_len, comp_obj, comp_len);
- if (comp_len < ff_pkt->object_len) {
- ff_pkt->object = comp_obj;
- ff_pkt->object_compression = 1; /* zlib level 9 compression */
- } else {
- /* Uncompressed object smaller, use it */
- comp_len = ff_pkt->object_len;
- }
- Dmsg2(100, "Object compressed from %d to %d bytes\n", ff_pkt->object_len, comp_len);
+ /* Big object, compress it */
+ comp_len = ff_pkt->object_len + 1000;
+ POOLMEM *comp_obj = get_memory(comp_len);
+ /* *** FIXME *** check Zdeflate error */
+ Zdeflate(ff_pkt->object, ff_pkt->object_len, comp_obj, comp_len);
+ if (comp_len < ff_pkt->object_len) {
+ ff_pkt->object = comp_obj;
+ ff_pkt->object_compression = 1; /* zlib level 9 compression */
+ } else {
+ /* Uncompressed object smaller, use it */
+ comp_len = ff_pkt->object_len;
+ }
+ Dmsg2(100, "Object compressed from %d to %d bytes\n", ff_pkt->object_len, comp_len);
}
sd->msglen = Mmsg(sd->msg, "%d %d %d %d %d %d %s%c%s%c",
- jcr->JobFiles, ff_pkt->type, ff_pkt->object_index,
- comp_len, ff_pkt->object_len, ff_pkt->object_compression,
- ff_pkt->fname, 0, ff_pkt->object_name, 0);
+ jcr->JobFiles, ff_pkt->type, ff_pkt->object_index,
+ comp_len, ff_pkt->object_len, ff_pkt->object_compression,
+ ff_pkt->fname, 0, ff_pkt->object_name, 0);
sd->msg = check_pool_memory_size(sd->msg, sd->msglen + comp_len + 2);
memcpy(sd->msg + sd->msglen, ff_pkt->object, comp_len);
/* Note we send one extra byte so Dir can store zero after object */
sd->msglen += comp_len + 1;
stat = sd->send();
if (ff_pkt->object_compression) {
- free_and_null_pool_memory(ff_pkt->object);
+ free_and_null_pool_memory(ff_pkt->object);
}
break;
case FT_REG:
stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%d%c", jcr->JobFiles,
- ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0,
- ff_pkt->delta_seq, 0);
+ ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0,
+ ff_pkt->delta_seq, 0);
break;
default:
stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
- ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0,
- attribsEx, 0, ff_pkt->delta_seq, 0);
+ ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0,
+ attribsEx, 0, ff_pkt->delta_seq, 0);
break;
}
Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
if (!stat && !jcr->is_job_canceled()) {
Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
- sd->bstrerror());
+ sd->bstrerror());
}
- sd->signal(BNET_EOD); /* indicate end of attributes data */
+ sd->signal(BNET_EOD); /* indicate end of attributes data */
return stat;
}
if ((bctx.ff_pkt->flags & FO_COMPRESS) && bctx.ff_pkt->Compress_algo == COMPRESS_GZIP) {
if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
- bctx.cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
- bctx.max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
+ bctx.cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
+ bctx.max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
} else {
- bctx.cbuf = (Bytef *)jcr->compress_buf;
- bctx.max_compress_len = jcr->compress_buf_size; /* set max length */
+ bctx.cbuf = (Bytef *)jcr->compress_buf;
+ bctx.max_compress_len = jcr->compress_buf_size; /* set max length */
}
- bctx.wbuf = jcr->compress_buf; /* compressed output here */
+ bctx.wbuf = jcr->compress_buf; /* compressed output here */
bctx.cipher_input = (uint8_t *)jcr->compress_buf; /* encrypt compressed data */
/**
*/
if (((z_stream*)jcr->pZLIB_compress_workset)->total_in == 0) {
- /** set gzip compression level - must be done per file */
- if ((zstat=deflateParams((z_stream*)jcr->pZLIB_compress_workset,
- bctx.ff_pkt->Compress_level, Z_DEFAULT_STRATEGY)) != Z_OK) {
- Jmsg(jcr, M_FATAL, 0, _("Compression deflateParams error: %d\n"), zstat);
- jcr->setJobStatus(JS_ErrorTerminated);
- return false;
- }
+ /** set gzip compression level - must be done per file */
+ if ((zstat=deflateParams((z_stream*)jcr->pZLIB_compress_workset,
+ bctx.ff_pkt->Compress_level, Z_DEFAULT_STRATEGY)) != Z_OK) {
+ Jmsg(jcr, M_FATAL, 0, _("Compression deflateParams error: %d\n"), zstat);
+ jcr->setJobStatus(JS_ErrorTerminated);
+ return false;
+ }
}
}
#endif
if ((bctx.ff_pkt->flags & FO_COMPRESS) && bctx.ff_pkt->Compress_algo == COMPRESS_LZO1X) {
if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
- bctx.cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
- bctx.cbuf2 = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE + sizeof(comp_stream_header);
- bctx.max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
+ bctx.cbuf = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE;
+ bctx.cbuf2 = (Bytef *)jcr->compress_buf + OFFSET_FADDR_SIZE + sizeof(comp_stream_header);
+ bctx.max_compress_len = jcr->compress_buf_size - OFFSET_FADDR_SIZE;
} else {
- bctx.cbuf = (Bytef *)jcr->compress_buf;
- bctx.cbuf2 = (Bytef *)jcr->compress_buf + sizeof(comp_stream_header);
- bctx.max_compress_len = jcr->compress_buf_size; /* set max length */
+ bctx.cbuf = (Bytef *)jcr->compress_buf;
+ bctx.cbuf2 = (Bytef *)jcr->compress_buf + sizeof(comp_stream_header);
+ bctx.max_compress_len = jcr->compress_buf_size; /* set max length */
}
bctx.ch.magic = COMPRESS_LZO1X;
bctx.ch.version = COMP_HEAD_VERSION;
- bctx.wbuf = jcr->compress_buf; /* compressed output here */
+ bctx.wbuf = jcr->compress_buf; /* compressed output here */
bctx.cipher_input = (uint8_t *)jcr->compress_buf; /* encrypt compressed data */
}
#endif
if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
ff_pkt->flags & FO_HFSPLUS)) {
if (ff_pkt->hfsinfo.rsrclength > 0) {
- int flags;
- int rsrc_stream;
- if (bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
- ff_pkt->ff_errno = errno;
- berrno be;
- Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open resource fork for \"%s\": ERR=%s.\n"),
- ff_pkt->fname, be.bstrerror());
- jcr->JobErrors++;
- if (is_bopen(&ff_pkt->bfd)) {
- bclose(&ff_pkt->bfd);
- }
- return true;
- }
- flags = ff_pkt->flags;
- ff_pkt->flags &= ~(FO_COMPRESS|FO_SPARSE|FO_OFFSETS);
- if (flags & FO_ENCRYPT) {
- rsrc_stream = STREAM_ENCRYPTED_MACOS_FORK_DATA;
- } else {
- rsrc_stream = STREAM_MACOS_FORK_DATA;
- }
- stat = send_data(bctx, rsrc_stream);
- ff_pkt->flags = flags;
- bclose(&ff_pkt->bfd);
- if (!stat) {
- return false;
- }
+ int flags;
+ int rsrc_stream;
+ if (bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
+ ff_pkt->ff_errno = errno;
+ berrno be;
+ Jmsg(jcr, M_NOTSAVED, -1, _(" Cannot open resource fork for \"%s\": ERR=%s.\n"),
+ ff_pkt->fname, be.bstrerror());
+ jcr->JobErrors++;
+ if (is_bopen(&ff_pkt->bfd)) {
+ bclose(&ff_pkt->bfd);
+ }
+ return true;
+ }
+ flags = ff_pkt->flags;
+ ff_pkt->flags &= ~(FO_COMPRESS|FO_SPARSE|FO_OFFSETS);
+ if (flags & FO_ENCRYPT) {
+ rsrc_stream = STREAM_ENCRYPTED_MACOS_FORK_DATA;
+ } else {
+ rsrc_stream = STREAM_MACOS_FORK_DATA;
+ }
+ stat = send_data(bctx, rsrc_stream);
+ ff_pkt->flags = flags;
+ bclose(&ff_pkt->bfd);
+ if (!stat) {
+ return false;
+ }
}
Dmsg1(300, "Saving Finder Info for \"%s\"\n", ff_pkt->fname);
pm_memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32);
sd->msglen = 32;
if (bctx.digest) {
- crypto_digest_update(bctx.digest, (uint8_t *)sd->msg, sd->msglen);
+ crypto_digest_update(bctx.digest, (uint8_t *)sd->msg, sd->msglen);
}
if (bctx.signing_digest) {
- crypto_digest_update(bctx.signing_digest, (uint8_t *)sd->msg, sd->msglen);
+ crypto_digest_update(bctx.signing_digest, (uint8_t *)sd->msg, sd->msglen);
}
sd->send();
sd->signal(BNET_EOD);
Dmsg3(400, "cbuf=0x%x rbuf=0x%x len=%u\n", bctx.cbuf, bctx.rbuf, sd->msglen);
((z_stream*)jcr->pZLIB_compress_workset)->next_in = (Bytef *)bctx.rbuf;
- ((z_stream*)jcr->pZLIB_compress_workset)->avail_in = sd->msglen;
+ ((z_stream*)jcr->pZLIB_compress_workset)->avail_in = sd->msglen;
((z_stream*)jcr->pZLIB_compress_workset)->next_out = bctx.cbuf;
- ((z_stream*)jcr->pZLIB_compress_workset)->avail_out = bctx.max_compress_len;
+ ((z_stream*)jcr->pZLIB_compress_workset)->avail_out = bctx.max_compress_len;
if ((zstat=deflate((z_stream*)jcr->pZLIB_compress_workset, Z_FINISH)) != Z_STREAM_END) {
- Jmsg(jcr, M_FATAL, 0, _("Compression deflate error: %d\n"), zstat);
- jcr->setJobStatus(JS_ErrorTerminated);
- return false;
+ Jmsg(jcr, M_FATAL, 0, _("Compression deflate error: %d\n"), zstat);
+ jcr->setJobStatus(JS_ErrorTerminated);
+ return false;
}
bctx.compress_len = ((z_stream*)jcr->pZLIB_compress_workset)->total_out;
/** reset zlib stream to be able to begin from scratch again */
if ((zstat=deflateReset((z_stream*)jcr->pZLIB_compress_workset)) != Z_OK) {
- Jmsg(jcr, M_FATAL, 0, _("Compression deflateReset error: %d\n"), zstat);
- jcr->setJobStatus(JS_ErrorTerminated);
- return false;
+ Jmsg(jcr, M_FATAL, 0, _("Compression deflateReset error: %d\n"), zstat);
+ jcr->setJobStatus(JS_ErrorTerminated);
+ return false;
}
Dmsg2(400, "GZIP compressed len=%d uncompressed len=%d\n", bctx.compress_len,
- sd->msglen);
+ sd->msglen);
- sd->msglen = bctx.compress_len; /* set compressed length */
+ sd->msglen = bctx.compress_len; /* set compressed length */
bctx.cipher_input_len = bctx.compress_len;
}
#endif
/** Do compression if turned on */
if (bctx.ff_pkt->flags & FO_COMPRESS && bctx.ff_pkt->Compress_algo == COMPRESS_LZO1X && jcr->LZO_compress_workset) {
- lzo_uint len; /* TODO: See with the latest patch how to handle lzo_uint with 64bit */
+ lzo_uint len; /* TODO: See with the latest patch how to handle lzo_uint with 64bit */
ser_declare;
ser_begin(bctx.cbuf, sizeof(comp_stream_header));
Dmsg3(400, "cbuf=0x%x rbuf=0x%x len=%u\n", bctx.cbuf, bctx.rbuf, sd->msglen);
lzores = lzo1x_1_compress((const unsigned char*)bctx.rbuf, sd->msglen, bctx.cbuf2,
- &len, jcr->LZO_compress_workset);
+ &len, jcr->LZO_compress_workset);
bctx.compress_len = len;
if (lzores == LZO_E_OK && bctx.compress_len <= bctx.max_compress_len) {
- /* complete header */
- ser_uint32(COMPRESS_LZO1X);
- ser_uint32(bctx.compress_len);
- ser_uint16(bctx.ch.level);
- ser_uint16(bctx.ch.version);
+ /* complete header */
+ ser_uint32(COMPRESS_LZO1X);
+ ser_uint32(bctx.compress_len);
+ ser_uint16(bctx.ch.level);
+ ser_uint16(bctx.ch.version);
} else {
- /** this should NEVER happen */
- Jmsg(jcr, M_FATAL, 0, _("Compression LZO error: %d\n"), lzores);
- jcr->setJobStatus(JS_ErrorTerminated);
- return false;
+ /** this should NEVER happen */
+ Jmsg(jcr, M_FATAL, 0, _("Compression LZO error: %d\n"), lzores);
+ jcr->setJobStatus(JS_ErrorTerminated);
+ return false;
}
Dmsg2(400, "LZO compressed len=%d uncompressed len=%d\n", bctx.compress_len,
- sd->msglen);
+ sd->msglen);
bctx.compress_len += sizeof(comp_stream_header); /* add size of header */
- sd->msglen = bctx.compress_len; /* set compressed length */
+ sd->msglen = bctx.compress_len; /* set compressed length */
bctx.cipher_input_len = bctx.compress_len;
}
#endif
last = MAX(last - 1, 0);
if (ff->snap_fname[last] == '/') {
- if (ff->fname[sp_first] == '/') { /* compare with the first character of the string (sp_first not sp_first-1) */
- ff->snap_fname[last] = 0;
- }
+ if (ff->fname[sp_first] == '/') { /* compare with the first character of the string (sp_first not sp_first-1) */
+ ff->snap_fname[last] = 0;
+ }
} else {
- if (ff->fname[sp_first] != '/') {
- pm_strcat(ff->snap_fname, "/");
- }
+ if (ff->fname[sp_first] != '/') {
+ pm_strcat(ff->snap_fname, "/");
+ }
}
pm_strcat(ff->snap_fname, ff->fname + sp_first);
last = MAX(last - 1, 0);
if (ff->snap_fname[last] == '/') {
- if (ff->link[sp_first] == '/') { /* compare with the first character of the string (sp_first not sp_first-1) */
- ff->snap_fname[last] = 0;
- }
+ if (ff->link[sp_first] == '/') { /* compare with the first character of the string (sp_first not sp_first-1) */
+ ff->snap_fname[last] = 0;
+ }
} else {
- if (ff->link[sp_first] != '/') {
- pm_strcat(ff->snap_fname, "/");
- }
+ if (ff->link[sp_first] != '/') {
+ pm_strcat(ff->snap_fname, "/");
+ }
}
pm_strcat(ff->snap_fname, ff->link + sp_first);
while (*in && !IsPathSeparator(*in)) {
out++; in++;
}
- if (*in) { /* Not at the end of the string */
+ if (*in) { /* Not at the end of the string */
out++; in++;
- numsep++; /* one separator seen */
+ numsep++; /* one separator seen */
}
for (stripped=0; stripped<count && *in; stripped++) {
while (*in && !IsPathSeparator(*in)) {
- in++; /* skip chars */
+ in++; /* skip chars */
}
if (*in) {
- numsep++; /* count separators seen */
- in++; /* skip separator */
+ numsep++; /* count separators seen */
+ in++; /* skip separator */
}
}
/* Copy to end */
- while (*in) { /* copy to end */
+ while (*in) { /* copy to end */
if (IsPathSeparator(*in)) {
- numsep++;
+ numsep++;
}
*out++ = *in++;
}
*out = 0;
Dmsg4(500, "stripped=%d count=%d numsep=%d sep>count=%d\n",
- stripped, count, numsep, numsep>count);
+ stripped, count, numsep, numsep>count);
return stripped==count && numsep>count;
}
*/
void strip_path(FF_PKT *ff_pkt)
{
- if (!ff_pkt->strip_snap_path &&
+ if (!ff_pkt->strip_snap_path &&
(!(ff_pkt->flags & FO_STRIPPATH) || ff_pkt->strip_path <= 0))
{
Dmsg1(200, "No strip for %s\n", ff_pkt->fname);
if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
pm_strcpy(ff_pkt->link_save, ff_pkt->link);
Dmsg2(500, "strcpy link_save=%d link=%d\n", strlen(ff_pkt->link_save),
- strlen(ff_pkt->link));
+ strlen(ff_pkt->link));
Dsm_check(200);
- }
+ }
if (ff_pkt->strip_snap_path) {
if (!do_snap_strip(ff_pkt)) {
- Dmsg1(0, "Something wrong with do_snap_strip(%s)\n", ff_pkt->fname);
- unstrip_path(ff_pkt);
- goto rtn;
+ Dmsg1(0, "Something wrong with do_snap_strip(%s)\n", ff_pkt->fname);
+ unstrip_path(ff_pkt);
+ goto rtn;
}
}
/** Strip links but not symlinks */
if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
if (!do_strip(ff_pkt->strip_path, ff_pkt->link)) {
- unstrip_path(ff_pkt);
+ unstrip_path(ff_pkt);
}
}
{
return;
}
-
+
strcpy(ff_pkt->fname, ff_pkt->fname_save);
if (ff_pkt->type != FT_LNK && ff_pkt->fname != ff_pkt->link) {
Dmsg2(10, "strcpy link=%s link_save=%s\n", ff_pkt->link,
- ff_pkt->link_save);
+ ff_pkt->link_save);
strcpy(ff_pkt->link, ff_pkt->link_save);
Dmsg2(10, "strcpy link=%d link_save=%d\n", strlen(ff_pkt->link),
- strlen(ff_pkt->link_save));
+ strlen(ff_pkt->link_save));
Dsm_check(200);
}
}
/* tell vss to close the backup session */
if (jcr->Snapshot) {
if (g_pVSSClient->CloseBackup()) {
- /* inform user about writer states */
- for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
- int msg_type = M_INFO;
- if (g_pVSSClient->GetWriterState(i) < 1) {
- msg_type = M_WARNING;
- jcr->JobErrors++;
- }
- Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
- }
+ /* inform user about writer states */
+ for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
+ int msg_type = M_INFO;
+ if (g_pVSSClient->GetWriterState(i) < 1) {
+ msg_type = M_WARNING;
+ jcr->JobErrors++;
+ }
+ Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
+ }
}
/* Generate Job global writer metadata */
WCHAR *metadata = g_pVSSClient->GetMetadata();
if (metadata) {
- FF_PKT *ff_pkt = jcr->ff;
- ff_pkt->fname = (char *)"*all*"; /* for all plugins */
- ff_pkt->type = FT_RESTORE_FIRST;
- ff_pkt->LinkFI = 0;
- ff_pkt->object_name = (char *)"job_metadata.xml";
- ff_pkt->object = (char *)metadata;
- ff_pkt->object_len = (wcslen(metadata) + 1) * sizeof(WCHAR);
- ff_pkt->object_index = (int)time(NULL);
- save_file(jcr, ff_pkt, true);
+ FF_PKT *ff_pkt = jcr->ff;
+ ff_pkt->fname = (char *)"*all*"; /* for all plugins */
+ ff_pkt->type = FT_RESTORE_FIRST;
+ ff_pkt->LinkFI = 0;
+ ff_pkt->object_name = (char *)"job_metadata.xml";
+ ff_pkt->object = (char *)metadata;
+ ff_pkt->object_len = (wcslen(metadata) + 1) * sizeof(WCHAR);
+ ff_pkt->object_index = (int)time(NULL);
+ save_file(jcr, ff_pkt, true);
}
}
#endif
/*
Bacula(R) - The Network Backup Solution
- Copyright (C) 2000-2015 Kern Sibbald
+ Copyright (C) 2000-2016 Kern Sibbald
The original author of Bacula is Kern Sibbald, with contributions
from many others, a complete list can be found in the file AUTHORS.
Public License, v3.0 ("AGPLv3") and some additional permissions and
terms pursuant to its AGPLv3 Section 7.
- This notice must be preserved when any source code is
+ This notice must be preserved when any source code is
conveyed and/or propagated.
Bacula(R) is a registered trademark of Kern Sibbald.
*/
//#define TEST_WORKER
-#ifdef TEST_WORKER
+#ifdef TEST_WORKER
#define ERROR_BUFFER_OVERFLOW 1
#define ERROR_SUCCESS 0
#endif
-
+
/* acl errors to report per job. */
#define ACL_MAX_ERROR_PRINT_PER_JOB 25
-
+
/* xattr errors to report per job. */
#define XATTR_MAX_ERROR_PRINT_PER_JOB 25
-
-/* Return values from acl subroutines. */
-enum bacl_rtn_code {
- bacl_rtn_fatal = -1,
- bacl_rtn_error = 0,
- bacl_rtn_ok = 1
-};
-
-/* Return values from xattr subroutines. */
-enum bxattr_rtn_code {
- bxattr_rtn_fatal = -1,
- bxattr_rtn_error = 0,
- bxattr_rtn_ok = 1
-};
#define FILE_DAEMON 1
#include "lib/htable.h"
#include "fd_plugins.h"
#include "fd_snapshot.h"
#include "findlib/find.h"
-#include "acl.h"
-#include "xattr.h"
+#include "xacl.h"
#include "jcr.h"
-#include "protos.h" /* file daemon prototypes */
+#include "protos.h" /* file daemon prototypes */
#include "lib/runscript.h"
#include "lib/breg.h"
#ifdef HAVE_LIBZ
-#include <zlib.h> /* compression headers */
+#include <zlib.h> /* compression headers */
#else
#define uLongf uint32_t
#endif
#include <lzo/lzo1x.h>
#endif
-extern CLIENT *me; /* "Global" Client resource */
-extern bool win32decomp; /* Use decomposition of BackupRead data */
+extern CLIENT *me; /* "Global" Client resource */
+extern bool win32decomp; /* Use decomposition of BackupRead data */
extern bool no_win32_write_errors; /* Ignore certain errors */
void terminate_filed(int sig);
/*
Bacula(R) - The Network Backup Solution
- Copyright (C) 2000-2015 Kern Sibbald
+ Copyright (C) 2000-2016 Kern Sibbald
The original author of Bacula is Kern Sibbald, with contributions
from many others, a complete list can be found in the file AUTHORS.
Public License, v3.0 ("AGPLv3") and some additional permissions and
terms pursuant to its AGPLv3 Section 7.
- This notice must be preserved when any source code is
+ This notice must be preserved when any source code is
conveyed and/or propagated.
Bacula(R) is a registered trademark of Kern Sibbald.
void start_dir_heartbeat(JCR *jcr);
void stop_dir_heartbeat(JCR *jcr);
-/* From acl.c */
-bool backup_acl_streams(JCR *jcr, FF_PKT *ff_pkt);
-bacl_rtn_code restore_acl_streams(JCR *jcr, int stream, char *content,
- uint32_t content_length);
-
/* from accurate.c */
bool accurate_finish(JCR *jcr);
bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt);
void strip_path(FF_PKT *ff_pkt);
void unstrip_path(FF_PKT *ff_pkt);
-/* from xattr.c */
-bool backup_xattr_streams(JCR *jcr, FF_PKT *ff_pkt);
-bxattr_rtn_code restore_xattr_streams(JCR *jcr, int stream,
- char *content, uint32_t content_length);
-
/* from job.c */
findINCEXE *new_exclude(JCR *jcr);
findINCEXE *new_preinclude(JCR *jcr);
/*
Bacula(R) - The Network Backup Solution
- Copyright (C) 2000-2015 Kern Sibbald
+ Copyright (C) 2000-2016 Kern Sibbald
Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
The original author of Bacula is Kern Sibbald, with contributions
Public License, v3.0 ("AGPLv3") and some additional permissions and
terms pursuant to its AGPLv3 Section 7.
- This notice must be preserved when any source code is
+ This notice must be preserved when any source code is
conveyed and/or propagated.
Bacula(R) is a registered trademark of Kern Sibbald.
/*
* Cleanup of delayed restore stack with streams for later processing.
- */
+ */
static void drop_delayed_restore_streams(r_ctx &rctx, bool reuse)
{
RESTORE_DATA_STREAM *rds;
* This can either be a delayed restore or direct restore.
*/
static inline bool do_restore_acl(JCR *jcr, int stream, char *content,
- uint32_t content_length)
+ uint32_t content_length)
{
- switch (restore_acl_streams(jcr, stream, content, content_length)) {
- case bacl_rtn_fatal:
- return false;
- case bacl_rtn_error:
- /*
- * Non-fatal errors, count them and when the number is under ACL_MAX_ERROR_PRINT_PER_JOB
- * print the error message set by the lower level routine in jcr->errmsg.
- */
- if (jcr->acl_ctx->nr_errors < ACL_MAX_ERROR_PRINT_PER_JOB) {
- Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
- }
- jcr->acl_ctx->nr_errors++;
- break;
- case bacl_rtn_ok:
- break;
+ switch (jcr->xacl->restore_acl(jcr, stream, content, content_length)) {
+ case bRC_XACL_fatal:
+ return false;
+ case bRC_XACL_error:
+ /*
+ * Non-fatal errors, count them and when the number is under ACL_MAX_ERROR_PRINT_PER_JOB
+ * print the error message set by the lower level routine in jcr->errmsg.
+ */
+ if (jcr->xacl->get_acl_nr_errors() < ACL_MAX_ERROR_PRINT_PER_JOB) {
+ Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+ }
+ break;
+ default:
+ break;
}
return true;
}
* This can either be a delayed restore or direct restore.
*/
static inline bool do_restore_xattr(JCR *jcr, int stream, char *content,
- uint32_t content_length)
+ uint32_t content_length)
{
- switch (restore_xattr_streams(jcr, stream, content, content_length)) {
- case bxattr_rtn_fatal:
- return false;
- case bxattr_rtn_error:
- /*
- * Non-fatal errors, count them and when the number is under XATTR_MAX_ERROR_PRINT_PER_JOB
- * print the error message set by the lower level routine in jcr->errmsg.
- */
- if (jcr->xattr_ctx->nr_errors < XATTR_MAX_ERROR_PRINT_PER_JOB) {
- Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
- }
- jcr->xattr_ctx->nr_errors++;
- break;
- case bxattr_rtn_ok:
- break;
+ switch (jcr->xacl->restore_xattr(jcr, stream, content, content_length)) {
+ case bRC_XACL_fatal:
+ return false;
+ case bRC_XACL_error:
+ /*
+ * Non-fatal errors, count them and when the number is under XATTR_MAX_ERROR_PRINT_PER_JOB
+ * print the error message set by the lower level routine in jcr->errmsg.
+ */
+ if (jcr->xacl->get_xattr_nr_errors() < XATTR_MAX_ERROR_PRINT_PER_JOB) {
+ Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+ }
+ break;
+ default:
+ break;
}
return true;
}
switch (rds->stream) {
case STREAM_UNIX_ACCESS_ACL:
case STREAM_UNIX_DEFAULT_ACL:
- case STREAM_ACL_AIX_TEXT:
- case STREAM_ACL_DARWIN_ACCESS:
- case STREAM_ACL_FREEBSD_DEFAULT:
- case STREAM_ACL_FREEBSD_ACCESS:
- case STREAM_ACL_HPUX_ACL_ENTRY:
- case STREAM_ACL_IRIX_DEFAULT:
- case STREAM_ACL_IRIX_ACCESS:
- case STREAM_ACL_LINUX_DEFAULT:
- case STREAM_ACL_LINUX_ACCESS:
- case STREAM_ACL_TRU64_DEFAULT:
- case STREAM_ACL_TRU64_DEFAULT_DIR:
- case STREAM_ACL_TRU64_ACCESS:
- case STREAM_ACL_SOLARIS_POSIX:
- case STREAM_ACL_SOLARIS_NFS4:
- case STREAM_ACL_AFS_TEXT:
- case STREAM_ACL_AIX_AIXC:
- case STREAM_ACL_AIX_NFS4:
- case STREAM_ACL_FREEBSD_NFS4:
- case STREAM_ACL_HURD_DEFAULT:
- case STREAM_ACL_HURD_ACCESS:
+ case STREAM_XACL_AIX_TEXT:
+ case STREAM_XACL_DARWIN_ACCESS:
+ case STREAM_XACL_FREEBSD_DEFAULT:
+ case STREAM_XACL_FREEBSD_ACCESS:
+ case STREAM_XACL_HPUX_ACL_ENTRY:
+ case STREAM_XACL_IRIX_DEFAULT:
+ case STREAM_XACL_IRIX_ACCESS:
+ case STREAM_XACL_LINUX_DEFAULT:
+ case STREAM_XACL_LINUX_ACCESS:
+ case STREAM_XACL_TRU64_DEFAULT:
+ case STREAM_XACL_TRU64_DEFAULT_DIR:
+ case STREAM_XACL_TRU64_ACCESS:
+ case STREAM_XACL_SOLARIS_POSIX:
+ case STREAM_XACL_SOLARIS_NFS4:
+ case STREAM_XACL_AFS_TEXT:
+ case STREAM_XACL_AIX_AIXC:
+ case STREAM_XACL_AIX_NFS4:
+ case STREAM_XACL_FREEBSD_NFS4:
+ case STREAM_XACL_HURD_DEFAULT:
+ case STREAM_XACL_HURD_ACCESS:
if (!do_restore_acl(jcr, rds->stream, rds->content, rds->content_length)) {
goto get_out;
}
break;
- case STREAM_XATTR_HURD:
- case STREAM_XATTR_IRIX:
- case STREAM_XATTR_TRU64:
- case STREAM_XATTR_AIX:
- case STREAM_XATTR_OPENBSD:
- case STREAM_XATTR_SOLARIS_SYS:
- case STREAM_XATTR_DARWIN:
- case STREAM_XATTR_FREEBSD:
- case STREAM_XATTR_LINUX:
- case STREAM_XATTR_NETBSD:
+ case STREAM_XACL_HURD_XATTR:
+ case STREAM_XACL_IRIX_XATTR:
+ case STREAM_XACL_TRU64_XATTR:
+ case STREAM_XACL_AIX_XATTR:
+ case STREAM_XACL_OPENBSD_XATTR:
+ case STREAM_XACL_SOLARIS_SYS_XATTR:
+ case STREAM_XACL_DARWIN_XATTR:
+ case STREAM_XACL_FREEBSD_XATTR:
+ case STREAM_XACL_LINUX_XATTR:
+ case STREAM_XACL_NETBSD_XATTR:
if (!do_restore_xattr(jcr, rds->stream, rds->content, rds->content_length)) {
goto get_out;
}
rds->content = NULL;
}
}
-
+
drop_delayed_restore_streams(rctx, true);
return true;
binit(&rctx.bfd);
binit(&rctx.forkbfd);
attr = rctx.attr = new_attr(jcr);
- if (have_acl) {
- jcr->acl_ctx = (acl_ctx_t *)malloc(sizeof(acl_ctx_t));
- memset(jcr->acl_ctx, 0, sizeof(acl_ctx_t));
- }
- if (have_xattr) {
- jcr->xattr_ctx = (xattr_ctx_t *)malloc(sizeof(xattr_ctx_t));
- memset(jcr->xattr_ctx, 0, sizeof(xattr_ctx_t));
- }
+ jcr->xacl = (XACL*)new_xacl();
Dsm_check(200);
while (fdmsg->bget_msg(&bmsg) >= 0 && !job_canceled(jcr)) {
case STREAM_UNIX_ACCESS_ACL:
case STREAM_UNIX_DEFAULT_ACL:
- case STREAM_ACL_AIX_TEXT:
- case STREAM_ACL_DARWIN_ACCESS:
- case STREAM_ACL_FREEBSD_DEFAULT:
- case STREAM_ACL_FREEBSD_ACCESS:
- case STREAM_ACL_HPUX_ACL_ENTRY:
- case STREAM_ACL_IRIX_DEFAULT:
- case STREAM_ACL_IRIX_ACCESS:
- case STREAM_ACL_LINUX_DEFAULT:
- case STREAM_ACL_LINUX_ACCESS:
- case STREAM_ACL_TRU64_DEFAULT:
- case STREAM_ACL_TRU64_DEFAULT_DIR:
- case STREAM_ACL_TRU64_ACCESS:
- case STREAM_ACL_SOLARIS_POSIX:
- case STREAM_ACL_SOLARIS_NFS4:
- case STREAM_ACL_AFS_TEXT:
- case STREAM_ACL_AIX_AIXC:
- case STREAM_ACL_AIX_NFS4:
- case STREAM_ACL_FREEBSD_NFS4:
- case STREAM_ACL_HURD_DEFAULT:
- case STREAM_ACL_HURD_ACCESS:
+ case STREAM_XACL_AIX_TEXT:
+ case STREAM_XACL_DARWIN_ACCESS:
+ case STREAM_XACL_FREEBSD_DEFAULT:
+ case STREAM_XACL_FREEBSD_ACCESS:
+ case STREAM_XACL_HPUX_ACL_ENTRY:
+ case STREAM_XACL_IRIX_DEFAULT:
+ case STREAM_XACL_IRIX_ACCESS:
+ case STREAM_XACL_LINUX_DEFAULT:
+ case STREAM_XACL_LINUX_ACCESS:
+ case STREAM_XACL_TRU64_DEFAULT:
+ case STREAM_XACL_TRU64_DEFAULT_DIR:
+ case STREAM_XACL_TRU64_ACCESS:
+ case STREAM_XACL_SOLARIS_POSIX:
+ case STREAM_XACL_SOLARIS_NFS4:
+ case STREAM_XACL_AFS_TEXT:
+ case STREAM_XACL_AIX_AIXC:
+ case STREAM_XACL_AIX_NFS4:
+ case STREAM_XACL_FREEBSD_NFS4:
+ case STREAM_XACL_HURD_DEFAULT:
+ case STREAM_XACL_HURD_ACCESS:
/*
* Do not restore ACLs when
* a) The current file is not extracted
}
break;
- case STREAM_XATTR_HURD:
- case STREAM_XATTR_IRIX:
- case STREAM_XATTR_TRU64:
- case STREAM_XATTR_AIX:
- case STREAM_XATTR_OPENBSD:
- case STREAM_XATTR_SOLARIS_SYS:
- case STREAM_XATTR_DARWIN:
- case STREAM_XATTR_FREEBSD:
- case STREAM_XATTR_LINUX:
- case STREAM_XATTR_NETBSD:
+ case STREAM_XACL_HURD_XATTR:
+ case STREAM_XACL_IRIX_XATTR:
+ case STREAM_XACL_TRU64_XATTR:
+ case STREAM_XACL_AIX_XATTR:
+ case STREAM_XACL_OPENBSD_XATTR:
+ case STREAM_XACL_SOLARIS_SYS_XATTR:
+ case STREAM_XACL_DARWIN_XATTR:
+ case STREAM_XACL_FREEBSD_XATTR:
+ case STREAM_XACL_LINUX_XATTR:
+ case STREAM_XACL_NETBSD_XATTR:
/*
* Do not restore Extended Attributes when
* a) The current file is not extracted
}
break;
- case STREAM_XATTR_SOLARIS:
+ case STREAM_XACL_SOLARIS_XATTR:
/*
* Do not restore Extended Attributes when
* a) The current file is not extracted
*/
Dmsg2(10, "End Do Restore. Files=%d Bytes=%s\n", jcr->JobFiles,
edit_uint64(jcr->JobBytes, ec1));
- if (have_acl && jcr->acl_ctx->nr_errors > 0) {
- Jmsg(jcr, M_WARNING, 0, _("Encountered %ld acl errors while doing restore\n"),
- jcr->acl_ctx->nr_errors);
+
+ if (jcr->xacl->get_acl_nr_errors() > 0) {
+ Jmsg(jcr, M_WARNING, 0, _("Encountered %ld acl errors while doing restore\n"), jcr->xacl->get_acl_nr_errors());
}
- if (have_xattr && jcr->xattr_ctx->nr_errors > 0) {
- Jmsg(jcr, M_WARNING, 0, _("Encountered %ld xattr errors while doing restore\n"),
- jcr->xattr_ctx->nr_errors);
+ if (jcr->xacl->get_xattr_nr_errors() > 0) {
+ Jmsg(jcr, M_WARNING, 0, _("Encountered %ld xattr errors while doing restore\n"), jcr->xacl->get_xattr_nr_errors());
}
+
if (non_suppored_data > 1 || non_suppored_attr > 1) {
Jmsg(jcr, M_WARNING, 0, _("%d non-supported data streams and %d non-supported attrib streams ignored.\n"),
non_suppored_data, non_suppored_attr);
- }
+ }
if (non_suppored_rsrc) {
Jmsg(jcr, M_INFO, 0, _("%d non-supported resource fork streams ignored.\n"), non_suppored_rsrc);
- }
+ }
if (non_suppored_finfo) {
Jmsg(jcr, M_INFO, 0, _("%d non-supported Finder Info streams ignored.\n"), non_suppored_finfo);
- }
+ }
if (non_suppored_acl) {
Jmsg(jcr, M_INFO, 0, _("%d non-supported acl streams ignored.\n"), non_suppored_acl);
- }
+ }
if (non_suppored_crypto) {
Jmsg(jcr, M_INFO, 0, _("%d non-supported crypto streams ignored.\n"), non_suppored_acl);
- }
+ }
if (non_suppored_xattr) {
Jmsg(jcr, M_INFO, 0, _("%d non-supported xattr streams ignored.\n"), non_suppored_xattr);
- }
-
+ }
+
/* Free Signature & Crypto Data */
free_signature(rctx);
free_session(rctx);
crypto_cipher_free(rctx.cipher_ctx.cipher);
rctx.cipher_ctx.cipher = NULL;
}
-
+
if (rctx.cipher_ctx.buf) {
free_pool_memory(rctx.cipher_ctx.buf);
rctx.cipher_ctx.buf = NULL;
jcr->compress_buf = NULL;
jcr->compress_buf_size = 0;
}
-
- if (have_acl && jcr->acl_ctx) {
- if (jcr->acl_ctx->content) {
- free(jcr->acl_ctx->content);
- }
- free(jcr->acl_ctx);
- jcr->acl_ctx = NULL;
- }
-
- if (have_xattr && jcr->xattr_ctx) {
- if (jcr->xattr_ctx->content) {
- free(jcr->xattr_ctx->content);
- }
- free(jcr->xattr_ctx);
- jcr->xattr_ctx = NULL;
- }
+
+ if (jcr->xacl) {
+ delete(jcr->xacl);
+ jcr->xacl = NULL;
+ }
/* Free the delayed stream stack list. */
if (rctx.delayed_streams) {
* NOTE! We only use uLong and Byte because they are
* needed by the zlib routines, they should not otherwise
* be used in Bacula.
- */
+ */
compress_len = jcr->compress_buf_size;
Dmsg2(200, "Comp_len=%d msglen=%d\n", compress_len, *length);
while ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
* and then buffer any remaining data. This should be effecient
* as long as Bacula's block size is not significantly smaller than the
* encryption block size (extremely unlikely!)
- */
+ */
unser_crypto_packet_len(cipher_ctx);
Dmsg1(500, "Crypto unser block size=%d\n", cipher_ctx->packet_len - CRYPTO_LEN_SIZE);
memmove(cipher_ctx->buf, &cipher_ctx->buf[cipher_ctx->packet_len],
cipher_ctx->buf_len);
}
- /* The packet was successfully written, reset the length so that
+ /* The packet was successfully written, reset the length so that
* the next packet length may be re-read by unser_crypto_packet_len() */
cipher_ctx->packet_len = 0;
}
/* Now perform the delayed restore of some specific data streams. */
rtn = pop_delayed_data_streams(rctx);
-
+
/* Verify the cryptographic signature, if any */
rctx.type = rctx.attr->type;
verify_signature(rctx);
}
return rtn;
-}
+}
/*
* In the context of jcr, flush any remaining data from the cipher context,
}
}
if (jcr->crypto.digest) {
- /* Use digest computed while writing the file to verify
+ /* Use digest computed while writing the file to verify
* the signature */
if ((err = crypto_sign_verify(sig, keypair, jcr->crypto.digest)) != CRYPTO_ERROR_NONE) {
Dmsg1(50, "Bad signature on %s\n", jcr->last_fname);
jcr->crypto.digest = digest;
/* Checksum the entire file
- * Make sure we don't modify JobBytes by saving and
+ * Make sure we don't modify JobBytes by saving and
* restoring it */
saved_bytes = jcr->JobBytes;
if (find_one_file(jcr, jcr->ff, do_file_digest, jcr->last_fname, (dev_t)-1, 1) != 0) {
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+/**
+ * Major refactoring of ACL and XATTR code written by:
+ *
+ * Radosław Korzeniewski, MMXVI
+ * radoslaw@korzeniewski.net, radekk@inteos.pl
+ * Inteos Sp. z o.o. http://www.inteos.pl/
+ *
+ *
+ * A specialized class to handle ACL and XATTR in Bacula Enterprise.
+ * The runtime consist of two parts:
+ * 1. OS independent class: XACL
+ * 2. OS dependent subclass: XACL_*
+ *
+ * OS dependent subclasses are available for the following OS:
+ * - Darwin (OSX)
+ * - FreeBSD (POSIX and NFSv4/ZFS acls)
+ * - Linux
+ * - Solaris (POSIX and NFSv4/ZFS acls)
+ *
+ * OS dependend subclasses in progress:
+ * - AIX (pre-5.3 and post 5.3 acls, acl_get and aclx_get interface)
+ * - HPUX
+ * - IRIX
+ * - Tru64
+ *
+ * OS independent class support AFS acls using the pioctl interface.
+ *
+ * ACLs are saved in OS native text format provided by acl(3) API and uses
+ * different streams for all different platforms.
+ * XATTRs are saved in OS independent format (Bacula own) and uses different streams
+ * for all different platforms. In theory it is possible to restore XATTRs from
+ * particular OS on different OS platform. But this functionality is not available.
+ * Above behavior is a backward compatibility with previous Bacula implementation
+ * we need to maintain.
+ *
+ * During OS specyfic implementation of XACL you need to implement a following methods:
+ *
+ * [xacl] - indicates xacl function/method to call
+ * [os] - indicates OS specyfic function, which could be different on specyfic OS
+ * (we use a Linux api calls as an example)
+ *
+ * ::os_get_acl(JCR *jcr, XACL_type xacltype)
+ *
+ * 1. get binary form of the acl - acl_get_file[os]
+ * 2. check if acl is trivial if required - call acl_issimple[xacl]
+ * 3. translate binary form into text representation - acl_to_text[os]
+ * 4. save acl text into content - set_content[xacl]
+ * 5. if acl not supported on filesystem - call clear_flag(XACL_FLAG_NATIVE)[xacl]
+ *
+ * ::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt)
+ *
+ * 1. call os_get_acl[xacl] for all supported ACL_TYPES
+ * 2. call send_acl_stream[xacl] for all supported ACL_STREAMS
+ *
+ * ::os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length)
+ *
+ * 1. prepare acl binary form from text representation stored in content - acl_from_text[os]
+ * 2. set acl on file - acl_set_file[os]
+ * 3. if acl not supported on filesystem, clear_flag(XACL_FLAG_NATIVE)
+ *
+ * ::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length)
+ *
+ * 1. call os_set_acl for all supported ACL_TYPES
+ *
+ * ::os_get_xattr_names (JCR *jcr, int namespace, POOLMEM ** pxlist, uint32_t * xlen)
+ *
+ * 1. get a size of the extended attibutes list for the file - llistxattr[os]
+ * in most os'es it is required to have a sufficient space for attibutes list
+ * and we wont allocate too much and too low space
+ * 2. allocate the buffer of required space
+ * 3. get an extended attibutes list for file - llistxattr[os]
+ * 4. return allocated space buffer in pxlist and length of the buffer in xlen
+ *
+ * ::os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen)
+ *
+ * 1. get a size of the extended attibute value for the file - lgetxattr[os]
+ * in most os'es it is required to have a sufficient space for attibute value
+ * and we wont allocate too much and too low space
+ * 2. allocate the buffer of required space
+ * 3. get an extended attibute value for file - lgetxattr[os]
+ * 4. return allocated space buffer in pvalue and length of the buffer in plen
+ *
+ * ::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt)
+ *
+ * 1. get a list of extended attributes (name and value) for a file; in most implementations
+ * it require to get a separate list of attributes names and separate values for every name,
+ * so it is:
+ * 1A. get a list of xattr attribute names available on file - os_get_xattr_names[xacl]
+ * 1B. for every attribute name get a value - os_get_xattr_value[xacl]
+ * You should skip some OS specyfic attributes like ACL attributes or NFS4; you can use
+ * check_xattr_skiplists[xacl] for this
+ * 1C. build a list [type alist] of name/value pairs stored in XACL_xattr struct
+ * 2. if the xattr list is not empty then serialize the list using serialize_xattr_stream[xacl]
+ * 3. call send_xattr_stream[xacl]
+ *
+ * ::os_set_xattr (JCR *jcr, XACL_xattr *xattr)
+ *
+ * 1. set xattr on file using name/value in xattr - lsetxattr[os]
+ * 2. if xattr not supported on filesystem - call clear_flag(XACL_FLAG_NATIVE)[xacl]
+ *
+ * ::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length)
+ *
+ * 1. unserialize backup stream
+ * 2. for every extended attribute restored call os_set_xattr[xacl] to set this attribute on file
+ */
+
+#include "bacula.h"
+#include "filed.h"
+
+/*
+ * This is a constructor of the base XACL class which is OS independent
+ *
+ * - for initialization it uses ::init()
+ *
+ */
+XACL::XACL (){
+ init();
+};
+
+/*
+ * This is a destructor of the XACL class
+ */
+XACL::~XACL (){
+ free_pool_memory(content);
+};
+
+/*
+ * Initialization routine
+ * - initializes all variables to required status
+ * - allocates required memory
+ */
+void XACL::init(){
+#if defined(HAVE_ACL)
+ acl_ena = TRUE;
+#else
+ acl_ena = FALSE;
+#endif
+
+#if defined(HAVE_XATTR)
+ xattr_ena = TRUE;
+#else
+ xattr_ena = FALSE;
+#endif
+
+ /* generic variables */
+ flags = XACL_FLAG_NONE;
+ current_dev = 0;
+ content = get_pool_memory(PM_BSOCK); /* it is better to have a 4k buffer */
+ content_len = 0;
+ acl_nr_errors = 0;
+ xattr_nr_errors = 0;
+ acl_streams = NULL;
+ default_acl_streams = NULL;
+ xattr_streams = NULL;
+ xattr_skiplist = NULL;
+ xattr_acl_skiplist = NULL;
+};
+
+/*
+ * Enables ACL handling in runtime, could be disabled with disable_acl
+ * when ACL is not configured then cannot change status
+ */
+void XACL::enable_acl(){
+#if defined(HAVE_ACL)
+ acl_ena = TRUE;
+#endif
+};
+
+/*
+ * Disables ACL handling in runtime, could be enabled with enable_acl
+ * when ACL is configured
+ */
+void XACL::disable_acl(){
+ acl_ena = FALSE;
+};
+
+/*
+ * Enables XATTR handling in runtime, could be disabled with disable_xattr
+ * when XATTR is not configured then cannot change status
+ */
+void XACL::enable_xattr(){
+#ifdef HAVE_XATTR
+ xattr_ena = TRUE;
+#endif
+};
+
+/*
+ * Disables XATTR handling in runtime, could be enabled with enable_xattr
+ * when XATTR is configured
+ */
+void XACL::disable_xattr(){
+ xattr_ena = FALSE;
+};
+
+/*
+ * Copies a text into a content variable and sets a constent_len respectively
+ *
+ * in:
+ * text - a standard null terminated string
+ * out:
+ * pointer to content variable to use externally
+ */
+POOLMEM * XACL::set_content(char *text){
+ content_len = pm_strcpy(&content, text);
+ return content;
+};
+
+/*
+ * Copies a data with length of len into a content variable
+ *
+ * in:
+ * data - data pointer to copy into content buffer
+ * out:
+ * pointer to content variable to use externally
+ */
+POOLMEM * XACL::set_content(char *data, int len){
+ content_len = pm_memcpy(&content, data, len);
+ return content;
+};
+
+/*
+ * Check if we changed the device,
+ * if so setup a flags
+ *
+ * in:
+ * jcr - Job Control Record
+ * out:
+ * bRC_XACL_ok - change of device checked and finish succesful
+ * bRC_XACL_error - encountered error
+ * bRC_XACL_skip - cannot verify device - no file found
+ * bRC_XACL_inval - invalid input data
+ */
+bRC_XACL XACL::check_dev (JCR *jcr){
+
+ int lst;
+ struct stat st;
+
+ /* sanity check of input variables */
+ if (jcr == NULL || jcr->last_fname == NULL){
+ return bRC_XACL_inval;
+ }
+
+ lst = lstat(jcr->last_fname, &st);
+ switch (lst){
+ case -1: {
+ berrno be;
+ switch (errno){
+ case ENOENT:
+ return bRC_XACL_skip;
+ default:
+ Mmsg2(jcr->errmsg, _("Unable to stat file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "Unable to stat file \"%s\": ERR=%s\n", jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ break;
+ }
+ case 0:
+ break;
+ }
+
+ check_dev(jcr, st.st_dev);
+
+ return bRC_XACL_ok;
+};
+
+/*
+ * Check if we changed the device, if so setup a flags
+ *
+ * in:
+ * jcr - Job Control Record
+ * out:
+ * internal flags status set
+ */
+void XACL::check_dev (JCR *jcr, uint32_t dev){
+
+ /* sanity check of input variables */
+ if (jcr == NULL || jcr->last_fname == NULL){
+ return;
+ }
+
+ if (current_dev != dev){
+ flags = XACL_FLAG_NONE;
+#if defined(HAVE_AFS_ACL)
+ /* handle special fs: AFS */
+ if (fstype_equals(jcr->last_fname, "afs")){
+ set_flag(XACL_FLAG_AFS);
+ } else {
+ set_flag(XACL_FLAG_NATIVE);
+ }
+#else
+ set_flag(XACL_FLAG_NATIVE);
+#endif
+ current_dev = dev;
+ }
+};
+
+/*
+ * It sends a stream located in this->content to Storage Daemon, so the main Bacula
+ * backup loop is free from this. It sends a header followed by data.
+ *
+ * in:
+ * jcr - Job Control Record
+ * stream - a stream number to save
+ * out:
+ * bRC_XACL_inval - when supplied variables are incorrect
+ * bRC_XACL_fatal - when we can't send data to the SD
+ * bRC_XACL_ok - send finish without errors
+ */
+bRC_XACL XACL::send_acl_stream(JCR *jcr, int stream){
+
+ BSOCK * sd;
+ POOLMEM * msgsave;
+#ifdef FD_NO_SEND_TEST
+ return bRC_XACL_ok;
+#endif
+
+ /* sanity check of input variables */
+ if (jcr == NULL || jcr->store_bsock == NULL){
+ return bRC_XACL_inval;
+ }
+ if (content_len <= 0){
+ return bRC_XACL_ok;
+ }
+
+ sd = jcr->store_bsock;
+ /* 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 bRC_XACL_fatal;
+ }
+
+ /* send the buffer to the storage deamon */
+ Dmsg1(400, "Backing up ACL <%s>\n", content);
+ msgsave = sd->msg;
+ sd->msg = content;
+ sd->msglen = content_len + 1;
+ 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 bRC_XACL_fatal;
+ }
+
+ 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 bRC_XACL_fatal;
+ }
+
+ Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
+ return bRC_XACL_ok;
+};
+
+/*
+ * It sends a stream located in this->content to Storage Daemon, so the main Bacula
+ * backup loop is free from this. It sends a header followed by data.
+ *
+ * in:
+ * jcr - Job Control Record
+ * stream - a stream number to save
+ * out:
+ * bRC_XACL_inval - when supplied variables are incorrect
+ * bRC_XACL_fatal - when we can't send data to the SD
+ * bRC_XACL_ok - send finish without errors
+ */
+bRC_XACL XACL::send_xattr_stream(JCR *jcr, int stream){
+
+ BSOCK * sd;
+ POOLMEM * msgsave;
+#ifdef FD_NO_SEND_TEST
+ return bRC_XACL_ok;
+#endif
+
+ /* sanity check of input variables */
+ if (jcr == NULL || jcr->store_bsock == NULL){
+ return bRC_XACL_inval;
+ }
+ if (content_len <= 0){
+ return bRC_XACL_ok;
+ }
+
+ sd = jcr->store_bsock;
+ /* 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 bRC_XACL_fatal;
+ }
+
+ /* send the buffer to the storage deamon */
+ Dmsg1(400, "Backing up XATTR <%s>\n", content);
+ msgsave = sd->msg;
+ sd->msg = content;
+ sd->msglen = content_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 bRC_XACL_fatal;
+ }
+
+ 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 bRC_XACL_fatal;
+ }
+ Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
+ return bRC_XACL_ok;
+};
+
+/*
+ * The main public backup method for ACL
+ *
+ * in:
+ * jcr - Job Control Record
+ * ff_pkt - file backup record
+ * out:
+ * bRC_XACL_fatal - when ACL backup is not compiled in Bacula
+ * bRC_XACL_ok - backup finish without problems
+ * bRC_XACL_error - when you can't backup acl data because some error
+ */
+bRC_XACL XACL::backup_acl (JCR *jcr, FF_PKT *ff_pkt){
+
+#if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
+ Jmsg(jcr, M_FATAL, 0, "ACL backup requested but not configured in Bacula.\n");
+ return bRC_XACL_fatal;
+#else
+ /* sanity check of input variables and verify if engine is enabled */
+ if (acl_ena && jcr != NULL && ff_pkt != NULL){
+ /* acl engine enabled, proceed */
+ bRC_XACL rc;
+ /*
+ * No acl request for link or plugin
+ *
+ * TODO: it should be possible to handle ACL/XATTR for cmd plugins
+ */
+ if (!(ff_pkt->flags & FO_ACL && ff_pkt->type != FT_LNK && !ff_pkt->cmd_plugin)){
+ return bRC_XACL_ok;
+ }
+
+ jcr->errmsg[0] = 0;
+ check_dev(jcr, ff_pkt->statp.st_dev);
+
+#if defined(HAVE_AFS_ACL)
+ if (flags & XACL_FLAG_AFS){
+ Dmsg0(400, "make AFS ACL call\n");
+ rc = afs_backup_acl(jcr, ff_pkt);
+ goto bail_out;
+ }
+#endif
+
+#if defined(HAVE_ACL)
+ if (flags & XACL_FLAG_NATIVE){
+ Dmsg0(400, "make Native ACL call\n");
+ rc = os_backup_acl(jcr, ff_pkt);
+ } else {
+ /* skip acl backup */
+ return bRC_XACL_ok;
+ }
+#endif
+
+#if defined(HAVE_AFS_ACL)
+ bail_out:
+#endif
+ if (rc == bRC_XACL_error){
+ if (acl_nr_errors < ACL_MAX_ERROR_PRINT_PER_JOB){
+ if (!jcr->errmsg[0]){
+ Jmsg(jcr, M_WARNING, 0, "No OS ACL configured.\n");
+ } else {
+ Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+ }
+ inc_acl_errors();
+ }
+ return bRC_XACL_ok;
+ }
+ return rc;
+ }
+ return bRC_XACL_ok;
+#endif
+};
+
+/*
+ * The main public restore method for ACL
+ *
+ * in:
+ * jcr - Job Control Record
+ * stream - a backup stream type number to restore_acl
+ * data - a potinter to the data stream to restore
+ * length - a data stream length
+ * out:
+ * bRC_XACL_fatal - when ACL restore is not compiled in Bacula
+ * bRC_XACL_ok - restore finish without problems
+ * bRC_XACL_error - when you can't restore a stream because some error
+ */
+bRC_XACL XACL::restore_acl (JCR *jcr, int stream, char *data, uint32_t length){
+
+#if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL)
+ Jmsg(jcr, M_FATAL, 0, "ACL retore requested but not configured in Bacula.\n");
+ return bRC_XACL_fatal;
+#else
+ /* sanity check of input variables and verify if engine is enabled */
+ if (acl_ena && jcr != NULL && data != NULL){
+ /* acl engine enabled, proceed */
+ int a;
+ bRC_XACL rc = check_dev(jcr);
+
+ switch (rc){
+ case bRC_XACL_skip:
+ return bRC_XACL_ok;
+ case bRC_XACL_ok:
+ break;
+ default:
+ return rc;
+ }
+
+ /* copy a data into a content buffer */
+ set_content(data, length);
+
+ switch (stream){
+#if defined(HAVE_AFS_ACL)
+ case STREAM_XACL_AFS_TEXT:
+ if (flags & XACL_FLAG_AFS){
+ return afs_restore_acl(jcr, stream);
+ } else {
+ /*
+ * Increment error count but don't log an error again for the same filesystem.
+ */
+ inc_acl_errors();
+ return bRC_XACL_ok;
+ }
+#endif
+#if defined(HAVE_ACL)
+ case STREAM_UNIX_ACCESS_ACL:
+ case STREAM_UNIX_DEFAULT_ACL:
+ if (flags & XACL_FLAG_NATIVE){
+ return os_restore_acl(jcr, stream, content, content_len);
+ } else {
+ inc_acl_errors();
+ return bRC_XACL_ok;
+ }
+ break;
+ default:
+ if (flags & XACL_FLAG_NATIVE){
+ for (a = 0; acl_streams[a] > 0; a++){
+ if (acl_streams[a] == stream){
+ return os_restore_acl(jcr, stream, content, content_len);
+ }
+ }
+ for (a = 0; default_acl_streams[a] > 0; a++){
+ if (default_acl_streams[a] == stream){
+ return os_restore_acl(jcr, stream, content, content_len);
+ }
+ }
+ } else {
+ inc_acl_errors();
+ return bRC_XACL_ok;
+ }
+ break;
+#else
+ default:
+ break;
+#endif
+ }
+ /* cannot find a valid stream to support */
+ Qmsg2(jcr, M_WARNING, 0, _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"), jcr->last_fname, stream);
+ return bRC_XACL_error;
+ }
+ return bRC_XACL_ok;
+#endif
+};
+
+/*
+ * The main public backup method for XATTR
+ *
+ * in:
+ * jcr - Job Control Record
+ * ff_pkt - file backup record
+ * out:
+ * bRC_XACL_fatal - when XATTR backup is not compiled in Bacula
+ * bRC_XACL_ok - backup finish without problems
+ * bRC_XACL_error - when you can't backup xattr data because some error
+ */
+bRC_XACL XACL::backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
+
+#if !defined(HAVE_XATTR)
+ Jmsg(jcr, M_FATAL, 0, "XATTR backup requested but not configured in Bacula.\n");
+ return bRC_XACL_fatal;
+#else
+ /* sanity check of input variables and verify if engine is enabled */
+ if (xattr_ena && jcr != NULL && ff_pkt != NULL){
+ /* xattr engine enabled, proceed */
+ bRC_XACL rc;
+ /*
+ * No xattr request for plugin
+ *
+ * TODO: it should be possible to handle ACL/XATTR for cmd plugins
+ */
+ if (!(ff_pkt->flags & FO_XATTR && !ff_pkt->cmd_plugin)){
+ return bRC_XACL_ok;
+ }
+
+ jcr->errmsg[0] = 0;
+ check_dev(jcr, ff_pkt->statp.st_dev);
+
+ if (flags & XACL_FLAG_NATIVE){
+ Dmsg0(400, "make Native XATTR call\n");
+ rc = os_backup_xattr(jcr, ff_pkt);
+ } else {
+ /* skip xattr backup */
+ return bRC_XACL_ok;
+ }
+
+ if (rc == bRC_XACL_error){
+ if (xattr_nr_errors < XATTR_MAX_ERROR_PRINT_PER_JOB){
+ if (!jcr->errmsg[0]){
+ Jmsg(jcr, M_WARNING, 0, "No OS XATTR configured.\n");
+ } else {
+ Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+ }
+ inc_xattr_errors();
+ }
+ return bRC_XACL_ok;
+ }
+ return rc;
+ }
+ return bRC_XACL_ok;
+#endif
+};
+
+/*
+ * The main public restore method for XATTR
+ *
+ * in:
+ * jcr - Job Control Record
+ * stream - a backup stream type number to restore_acl
+ * data - a potinter to the data stream to restore
+ * length - a data stream length
+ * out:
+ * bRC_XACL_fatal - when XATTR restore is not compiled in Bacula
+ * bRC_XACL_ok - restore finish without problems
+ * bRC_XACL_error - when you can't restore a stream because some error
+ */
+bRC_XACL XACL::restore_xattr (JCR *jcr, int stream, char *data, uint32_t length){
+
+#if !defined(HAVE_XATTR)
+ Jmsg(jcr, M_FATAL, 0, "XATTR retore requested but not configured in Bacula.\n");
+ return bRC_XACL_fatal;
+#else
+ /* sanity check of input variables and verify if engine is enabled */
+ if (xattr_ena && jcr != NULL && data != NULL){
+ /* xattr engine enabled, proceed */
+ int a;
+ bRC_XACL rc = check_dev(jcr);
+
+ switch (rc){
+ case bRC_XACL_skip:
+ return bRC_XACL_ok;
+ case bRC_XACL_ok:
+ break;
+ default:
+ return rc;
+ }
+
+ /* copy a data into a content buffer */
+ set_content(data, length);
+
+ if (flags & XACL_FLAG_NATIVE){
+ for (a = 0; xattr_streams[a] > 0; a++){
+ if (xattr_streams[a] == stream){
+ return os_restore_xattr(jcr, stream, content, content_len);
+ }
+ }
+ } else {
+ inc_xattr_errors();
+ return bRC_XACL_ok;
+ }
+ /* cannot find a valid stream to support */
+ Qmsg2(jcr, M_WARNING, 0, _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"), jcr->last_fname, stream);
+ return bRC_XACL_error;
+ }
+ return bRC_XACL_ok;
+#endif
+};
+
+/*
+ * Performs a generic ACL backup using OS specyfic methods for
+ * getting acl data from file
+ *
+ * in:
+ * jcr - Job Control Record
+ * ff_pkt - file to backup control package
+ * out:
+ * bRC_XACL_ok - backup of acl's was successful
+ * bRC_XACL_fatal - was an error during acl backup
+ */
+bRC_XACL XACL::generic_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
+
+ /* sanity check of input variables */
+ if (jcr == NULL || ff_pkt == NULL){
+ return bRC_XACL_inval;
+ }
+
+ if (os_get_acl(jcr, XACL_TYPE_ACCESS) == bRC_XACL_fatal){
+ /* XXX: check if os_get_acl return fatal and decide what to do when error is returned */
+ return bRC_XACL_fatal;
+ }
+
+ if (content_len > 0){
+ if (send_acl_stream(jcr, acl_streams[0]) == bRC_XACL_fatal){
+ return bRC_XACL_fatal;
+ }
+ }
+
+ if (ff_pkt->type == FT_DIREND){
+ if (os_get_acl(jcr, XACL_TYPE_DEFAULT) == bRC_XACL_fatal){
+ return bRC_XACL_fatal;
+ }
+ if (content_len > 0){
+ if (send_acl_stream(jcr, default_acl_streams[0]) == bRC_XACL_fatal){
+ return bRC_XACL_fatal;
+ }
+ }
+ }
+ return bRC_XACL_ok;
+};
+
+/*
+ * Performs a generic ACL restore using OS specyfic methods for
+ * setting acl data on file.
+ *
+ * in:
+ * jcr - Job Control Record
+ * stream - a stream number to restore
+ * out:
+ * bRC_XACL_ok - backup of acl's was successful
+ * bRC_XACL_error - was an error during acl backup
+ * bRC_XACL_fatal - was a fatal error during acl backup or input data is invalid
+ */
+bRC_XACL XACL::generic_restore_acl (JCR *jcr, int stream){
+
+ unsigned int count;
+
+ /* sanity check of input variables */
+ if (jcr == NULL){
+ return bRC_XACL_inval;
+ }
+
+ switch (stream){
+ case STREAM_UNIX_ACCESS_ACL:
+ return os_set_acl(jcr, XACL_TYPE_ACCESS, content, content_len);
+ case STREAM_UNIX_DEFAULT_ACL:
+ return os_set_acl(jcr, XACL_TYPE_DEFAULT, content, content_len);
+ default:
+ for (count = 0; acl_streams[count] > 0; count++){
+ if (acl_streams[count] == stream){
+ return os_set_acl(jcr, XACL_TYPE_ACCESS, content, content_len);
+ }
+ }
+ for (count = 0; default_acl_streams[count] > 0; count++){
+ if (default_acl_streams[count] == stream){
+ return os_set_acl(jcr, XACL_TYPE_DEFAULT, content, content_len);
+ }
+ }
+ break;
+ }
+ return bRC_XACL_error;
+};
+
+/*
+ * Checks if supplied xattr attribute name is indicated on OS specyfic lists
+ *
+ * in:
+ * jcr - Job Control Record
+ * ff_pkt - file to backup control package
+ * name - a name of the attribute to check
+ * out:
+ * TRUE - the attribute name is found on OS specyfic skip lists and should be skipped during backup
+ * FALSE - the attribute should be saved on backup stream
+ */
+bool XACL::check_xattr_skiplists (JCR *jcr, FF_PKT *ff_pkt, char * name){
+
+ bool skip = FALSE;
+ int count;
+
+ /* sanity check of input variables */
+ if (jcr == NULL || ff_pkt == NULL || name == NULL){
+ return false;
+ }
+
+ /*
+ * On some OSes 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){
+ for (count = 0; xattr_acl_skiplist[count] != NULL; count++){
+ if (bstrcmp(name, xattr_acl_skiplist[count])){
+ skip = true;
+ break;
+ }
+ }
+ }
+ /* on some OSes we want to skip certain xattrs which are in the xattr_skiplist array. */
+ if (!skip){
+ for (count = 0; xattr_skiplist[count] != NULL; count++){
+ if (bstrcmp(name, xattr_skiplist[count])){
+ skip = true;
+ break;
+ }
+ }
+ }
+
+ return skip;
+};
+
+
+/*
+ * Performs generic XATTR backup using OS specyfic methods for
+ * getting xattr data from files - os_get_xattr_names and os_get_xattr_value
+ *
+ * in:
+ * jcr - Job Control Record
+ * ff_pkt - file to backup control package
+ * out:
+ * bRC_XACL_ok - xattr backup ok or no xattr to backup found
+ * bRC_XACL_error/fatal - an error or fatal error occurred
+ * bRC_XACL_inval - input variables was invalid
+ */
+bRC_XACL XACL::generic_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
+
+ bRC_XACL rc;
+ POOLMEM *xlist;
+ uint32_t xlen;
+ char *name;
+ uint32_t name_len;
+ POOLMEM *value;
+ uint32_t value_len;
+ bool skip;
+ alist *xattr_list = NULL;
+ int xattr_count = 0;
+ uint32_t len = 0;
+ XACL_xattr *xattr;
+
+ /* sanity check of input variables */
+ if (jcr == NULL || ff_pkt == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* xlist is allocated as POOLMEM by os_get_xattr_names */
+ rc = os_get_xattr_names(jcr, &xlist, &xlen);
+ switch (rc){
+ case bRC_XACL_ok:
+ /* it's ok, so go further */
+ break;
+ case bRC_XACL_skip:
+ case bRC_XACL_cont:
+ /* no xattr available, so skip rest of it */
+ return bRC_XACL_ok;
+ default:
+ return rc;
+ }
+
+ /* follow the list of xattr names and get the values
+ * TODO: change a standard NULL-terminated list of names into alist of structures */
+ for (name = xlist; (name - xlist) + 1 < xlen; name = strchr(name, '\0') + 1){
+
+ name_len = strlen(name);
+ skip = check_xattr_skiplists(jcr, ff_pkt, name);
+ if (skip || name_len == 0){
+ Dmsg1(100, "Skipping xattr named \"%s\"\n", name);
+ continue;
+ }
+
+ /* value is allocated as POOLMEM by os_get_xattr_value */
+ rc = os_get_xattr_value(jcr, name, &value, &value_len);
+ switch (rc){
+ case bRC_XACL_ok:
+ /* it's ok, so go further */
+ break;
+ case bRC_XACL_skip:
+ /* no xattr available, so skip rest of it */
+ free_pool_memory(xlist);
+ return bRC_XACL_ok;
+ default:
+ /* error / fatal */
+ free_pool_memory(xlist);
+ return rc;
+ }
+
+ /*
+ * we have a name of the extended attribute in the name variable
+ * and value of the extended attribute in the value variable
+ * so we need to build a list
+ */
+ xattr = (XACL_xattr*)malloc(sizeof(XACL_xattr));
+ xattr->name_len = name_len;
+ xattr->name = name;
+ xattr->value_len = value_len;
+ xattr->value = value;
+ /* magic name_len name value_len value */
+ len += sizeof(uint32_t) + sizeof(uint32_t) + name_len + sizeof(uint32_t) + value_len;
+
+ if (xattr_list == NULL){
+ xattr_list = New(alist(10, not_owned_by_alist));
+ }
+ xattr_list->append(xattr);
+ xattr_count++;
+ }
+ if (xattr_count > 0){
+ /* serialize the stream */
+ rc = serialize_xattr_stream(jcr, len, xattr_list);
+ if (rc != bRC_XACL_ok){
+ Mmsg(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"), jcr->last_fname);
+ Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n", jcr->last_fname);
+ goto bailout;
+ } else {
+ /* send data to SD */
+ rc = send_xattr_stream(jcr, xattr_streams[0]);
+ }
+ } else {
+ rc = bRC_XACL_ok;
+ }
+
+bailout:
+ /* free allocated data */
+ if (xattr_list != NULL){
+ foreach_alist(xattr, xattr_list){
+ if (xattr == NULL){
+ break;
+ }
+ if (xattr->value){
+ free_pool_memory(xattr->value);
+ }
+ free(xattr);
+ }
+ delete xattr_list;
+ }
+ if (xlist != NULL){
+ free_pool_memory(xlist);
+ }
+
+ return rc;
+};
+
+/*
+ * Performs a generic XATTR restore using OS specyfic methods for
+ * setting XATTR data on file.
+ *
+ * in:
+ * jcr - Job Control Record
+ * stream - a stream number to restore
+ * out:
+ * bRC_XACL_ok - restore of acl's was successful
+ * bRC_XACL_error - was an error during xattr restore
+ * bRC_XACL_fatal - was a fatal error during xattr restore
+ * bRC_XACL_inval - input variables was invalid
+ */
+bRC_XACL XACL::generic_restore_xattr (JCR *jcr, int stream){
+
+ bRC_XACL rc = bRC_XACL_ok;
+ alist *xattr_list;
+ XACL_xattr *xattr;
+
+ /* sanity check of input variables */
+ if (jcr == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* empty list */
+ xattr_list = New(alist(10, not_owned_by_alist));
+
+ /* unserialize data */
+ unserialize_xattr_stream(jcr, content, content_len, xattr_list);
+
+ /* follow the list to set all attributes */
+ foreach_alist(xattr, xattr_list){
+ rc = os_set_xattr(jcr, xattr);
+ if (rc != bRC_XACL_ok){
+ Dmsg2(100, "Failed to set extended attribute %s on file \"%s\"\n", xattr->name, jcr->last_fname);
+ goto bailout;
+ }
+ }
+
+bailout:
+ /* free allocated data */
+ if (xattr_list != NULL){
+ foreach_alist(xattr, xattr_list){
+ if (xattr == NULL){
+ break;
+ }
+ if (xattr->name){
+ free(xattr->name);
+ }
+ if (xattr->value){
+ free(xattr->value);
+ }
+ free(xattr);
+ }
+ delete xattr_list;
+ }
+ return rc;
+};
+
+/*
+ * Initialize variables acl_streams and default_acl_streams for a specified OS.
+ * The rutine should be called from object instance constructor
+ *
+ * in:
+ * pacl - acl streams supported for specyfic OS
+ * pacl_def - default (directory) acl streams supported for specyfic OS
+ */
+void XACL::set_acl_streams (const int *pacl, const int *pacl_def){
+
+ acl_streams = pacl;
+ default_acl_streams = pacl_def;
+};
+
+/*
+ * Initialize a variable xattr_streams for a specified OS.
+ * The rutine should be called from object instance constructor
+ *
+ * in:
+ * pxattr - xattr streams supported for specyfic OS
+ */
+void XACL::set_xattr_streams (const int *pxattr){
+
+ xattr_streams = pxattr;
+};
+
+/*
+ * Initialize variables xattr_skiplist and xattr_acl_skiplist for a specified OS.
+ * The rutine should be called from object instance constructor
+ *
+ * in:
+ * pxattr - xattr skip list for specyfic OS
+ * pxattr_acl - xattr acl names skip list for specyfic OS
+ */
+void XACL::set_xattr_skiplists (const char **pxattr, const char **pxattr_acl){
+
+ xattr_skiplist = pxattr;
+ xattr_acl_skiplist = pxattr_acl;
+};
+
+/*
+ * Serialize the XATTR stream which will be saved into archive. Serialization elements cames from
+ * a list and for backward compatibility we produce the same stream as prievous Bacula versions.
+ *
+ * serialized stream consists of the following elements:
+ * magic - A magic string which makes it easy to detect any binary incompatabilites
+ * required for backward compatibility
+ * name_len - The length of the following xattr name
+ * name - The name of the extended attribute
+ * value_len - The length of the following xattr data
+ * value - The actual content of the extended attribute only if value_len is greater then zero
+ *
+ * in:
+ * jcr - Job Control Record
+ * len - expected serialize length
+ * list - a list of xattr elements to serialize
+ * out:
+ * bRC_XACL_ok - when serialization was perfect
+ * bRC_XACL_inval - when we have invalid variables
+ * bRC_XACL_error - illegal attribute name
+ */
+bRC_XACL XACL::serialize_xattr_stream(JCR *jcr, uint32_t len, alist *list){
+
+ ser_declare;
+ XACL_xattr *xattr;
+
+ /* sanity check of input variables */
+ if (jcr == NULL || list == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* we serialize data direct to content buffer, so check if data fits */
+ content = check_pool_memory_size(content, len + 20);
+ ser_begin(content, len + 20);
+
+ foreach_alist(xattr, list){
+ if (xattr == NULL){
+ break;
+ }
+ /*
+ * serialize data
+ *
+ * we have to start with the XATTR_MAGIC for backward compatibility (the magic is silly)
+ */
+ ser_uint32(XATTR_MAGIC);
+ /* attribute name length and name itself */
+ if (xattr->name_len > 0 && xattr->name){
+ ser_uint32(xattr->name_len);
+ ser_bytes(xattr->name, xattr->name_len);
+ } else {
+ /* error - name cannot be empty */
+ Mmsg0(jcr->errmsg, _("Illegal empty xattr attribute name\n"));
+ Dmsg0(100, "Illegal empty xattr attribute name\n");
+ return bRC_XACL_error;
+ }
+ /* attibute value length and value itself */
+ ser_uint32(xattr->value_len);
+ if (xattr->value_len > 0 && xattr->value){
+ ser_bytes(xattr->value, xattr->value_len);
+ Dmsg3(100, "Backup xattr named %s, value %*.s\n", xattr->name, xattr->value_len, xattr->value);
+ } else {
+ Dmsg1(100, "Backup empty xattr named %s\n", xattr->name);
+ }
+ }
+
+ ser_end(content, len + 20);
+ content_len = ser_length(content);
+
+ return bRC_XACL_ok;
+};
+
+/*
+ * Unserialize XATTR stream on *content and produce a xattr *list which contain
+ * key => value pairs
+ *
+ * in:
+ * jcr - Job Control Record
+ * content - a stream content to unserialize
+ * length - a content length
+ * list - a pointer to the xattr list to populate
+ * out:
+ * bRC_XACL_ok - when unserialize was perfect
+ * bRC_XACL_inval - when we have invalid variables
+ * list - key/value pairs populated xattr list
+ */
+bRC_XACL XACL::unserialize_xattr_stream(JCR *jcr, char *content, uint32_t length, alist *list){
+
+ unser_declare;
+ uint32_t magic;
+ XACL_xattr *xattr;
+
+ /* sanity check of input variables */
+ if (jcr == NULL || content == NULL || list == NULL){
+ return bRC_XACL_inval;
+ }
+
+ unser_begin(content, length);
+ while (unser_length(content) < length){
+ /*
+ * Sanity check of correct stream magic number
+ * Someone was too paranoid to implement this kind of verification in original Bacula code
+ * Unfortunate for backward compatibility we have to follow this insane implementation
+ *
+ * XXX: design a new xattr stream format
+ */
+ unser_uint32(magic);
+ if (magic != XATTR_MAGIC){
+ Mmsg(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"), jcr->last_fname);
+ Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n", jcr->last_fname);
+ return bRC_XACL_error;
+ }
+ /* first attribute name length */
+ xattr = (XACL_xattr *)malloc(sizeof(XACL_xattr));
+ unser_uint32(xattr->name_len);
+ if (xattr->name_len == 0){
+ /* attribute name cannot be empty */
+ Mmsg(jcr->errmsg, _("Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n"), jcr->last_fname);
+ Dmsg1(100, "Illegal xattr stream, xattr name length <= 0 on file \"%s\"\n", jcr->last_fname);
+ free(xattr);
+ return bRC_XACL_error;
+ }
+ /* followed by attribute name itself */
+ xattr->name = (char *)malloc(xattr->name_len + 1);
+ unser_bytes(xattr->name, xattr->name_len);
+ xattr->name[xattr->name_len] = '\0';
+ /* attribute value */
+ unser_uint32(xattr->value_len);
+ if (xattr->value_len > 0){
+ /* we have a value */
+ xattr->value = (char *)malloc(xattr->value_len + 1);
+ unser_bytes(xattr->value, xattr->value_len);
+ xattr->value[xattr->value_len] = '\0';
+ Dmsg3(100, "Restoring xattr named %s, value %.*s\n", xattr->name, xattr->value_len, xattr->value);
+ } else {
+ /* value is empty */
+ xattr->value = NULL;
+ Dmsg1(100, "Restoring empty xattr named %s\n", xattr->name);
+ }
+ list->append(xattr);
+ }
+ unser_end(content, length);
+
+ return bRC_XACL_ok;
+};
+
+#if defined(HAVE_AFS_ACL)
+
+#if defined(HAVE_AFS_AFSINT_H) && defined(HAVE_AFS_VENUS_H)
+#include <afs/afsint.h>
+#include <afs/venus.h>
+#else
+#error "configure failed to detect availability of afs/afsint.h and/or afs/venus.h"
+#endif
+
+/*
+ * External references to functions in the libsys library function not in current include files.
+ */
+extern "C" {
+long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow);
+}
+
+/*
+ * Backup ACL data of AFS
+ *
+ * in:
+ * jcr - Job Control Record
+ * ff_pkt - file backup record
+ * out:
+ * bRC_XACL_inval - input variables are invalid (NULL)
+ * bRC_XACL_ok - backup finish without problems
+ * bRC_XACL_error - when you can't backup acl data because some error
+ */
+bRC_XACL XACL::afs_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
+
+ int rc;
+ struct ViceIoctl vip;
+ char data[BUFSIZ];
+
+ /* sanity check of input variables */
+ if (jcr == NULL || ff_pkt == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* AFS ACLs can only be set on a directory, so no need to try other files */
+ if (ff_pkt->type != FT_DIREND){
+ return bRC_XACL_ok;
+ }
+
+ vip.in = NULL;
+ vip.in_size = 0;
+ vip.out = data;
+ vip.out_size = BUFSIZE;
+ memset(data, 0, BUFSIZE);
+
+ if ((rc = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0){
+ berrno be;
+
+ Mmsg2(jcr->errmsg, _("pioctl VIOCGETAL error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "pioctl VIOCGETAL error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ set_content(data);
+ return send_acl_stream(jcr, STREAM_XACL_AFS_TEXT);
+};
+
+/*
+ * Restore ACL data of AFS
+ * in:
+ * jcr - Job Control Record
+ * stream - a backup stream type number to restore_acl
+ * out:
+ * bRC_XACL_inval - input variables are invalid (NULL)
+ * bRC_XACL_ok - backup finish without problems
+ * bRC_XACL_error - when you can't backup acl data because some error
+ */
+bRC_XACL XACL::afs_restore_acl (JCR *jcr, int stream){
+
+ int rc;
+ struct ViceIoctl vip;
+
+ /* sanity check of input variables */
+ if (jcr == NULL || ff_pkt == NULL){
+ return bRC_XACL_inval;
+ }
+
+ vip.in = content;
+ vip.in_size = content_len;
+ vip.out = NULL;
+ vip.out_size = 0;
+
+ if ((rc = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0){
+ berrno be;
+
+ Mmsg2(jcr->errmsg, _("pioctl VIOCSETAL error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "pioctl VIOCSETAL error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+
+ return bRC_XACL_error;
+ }
+ return bRC_XACL_ok;
+};
+#endif /* HAVE_AFS_ACL */
+
+#include "xacl_osx.h"
+#include "xacl_linux.h"
+#include "xacl_freebsd.h"
+#include "xacl_solaris.h"
+// #include "xacl_aix.h"
+
+/*
+ * Creating the corrent instance of the XACL for a supported OS
+ */
+void *new_xacl(){
+#if defined(HAVE_DARWIN_OS)
+ return new XACL_OSX();
+#elif defined(HAVE_LINUX_OS)
+ return new XACL_Linux();
+#elif defined(HAVE_FREEBSD_OS)
+ return new XACL_FreeBSD();
+#elif defined(HAVE_HURD_OS)
+ return new XACL_Hurd();
+#elif defined(HAVE_AIX_OS)
+ return new XACL_AIX();
+#elif defined(HAVE_IRIX_OS)
+ return new XACL_IRIX();
+#elif defined(HAVE_OSF1_OS)
+ return new XACL_OSF1();
+#elif defined(HAVE_SUN_OS)
+ return new XACL_Solaris();
+#endif
+};
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+/**
+ * Major refactoring of ACL and XATTR code written by:
+ *
+ * Radosław Korzeniewski, MMXVI
+ * radoslaw@korzeniewski.net, radekk@inteos.pl
+ * Inteos Sp. z o.o. http://www.inteos.pl/
+ *
+ */
+
+#ifndef __BXACL_H_
+#define __BXACL_H_
+
+/*
+ * Magic used in the magic field of the xattr struct.
+ * This way we can see if we encounter a valid xattr struct.
+ * Used for backward compatibility only.
+ */
+#define XATTR_MAGIC 0x5C5884
+
+/*
+ * Return value status enumeration
+ * You have an error when value is less then zero.
+ * You have a positive status when value is not negative
+ * (greater or equal to zero).
+ */
+enum bRC_XACL {
+ bRC_XACL_inval = -3, // input data invalid
+ bRC_XACL_fatal = -2, // a fatal error
+ bRC_XACL_error = -1, // standard error
+ bRC_XACL_ok = 0, // success
+ bRC_XACL_skip = 1, // processing should skip current runtime
+ bRC_XACL_cont = 2 // processing should skip current element
+ // and continue with next one
+};
+
+/*
+ * We support the following types of ACLs
+ */
+typedef enum {
+ XACL_TYPE_NONE = 0,
+ XACL_TYPE_ACCESS = 1,
+ XACL_TYPE_DEFAULT = 2,
+ XACL_TYPE_DEFAULT_DIR = 3,
+ XACL_TYPE_EXTENDED = 4,
+ XACL_TYPE_NFS4 = 5,
+ XACL_TYPE_PLUGIN = 6
+} XACL_type;
+
+/*
+ * Flags which control what ACL/XATTR engine
+ * to use for backup/restore
+ */
+#define XACL_FLAG_NONE 0
+#define XACL_FLAG_NATIVE 0x01
+#define XACL_FLAG_AFS 0x02
+#define XACL_FLAG_PLUGIN 0x04
+
+/*
+ * Ensure we have none
+ */
+#ifndef ACL_TYPE_NONE
+#define ACL_TYPE_NONE 0x0
+#endif
+
+/*
+ * Extended attribute (xattr) list element.
+ *
+ * Every xattr consist of a Key=>Value pair where
+ * both could be a binary data.
+ */
+struct XACL_xattr {
+ uint32_t name_len;
+ char *name;
+ uint32_t value_len;
+ char *value;
+};
+
+/*
+ * Basic ACL/XATTR class which is a foundation for any other OS specyfic implementation.
+ *
+ * This class cannot be used directly as it is an abstraction class with a lot of virtual
+ * methods laying around. As a basic class it has all public API available for backup and
+ * restore functionality. As a bonus it handles all ACL/XATTR generic functions and OS
+ * independent API, i.e. for AFS ACL/XATTR or Plugins ACL/XATTR (future functionality).
+ */
+class XACL {
+private:
+ bool acl_ena;
+ bool xattr_ena;
+ uint32_t flags;
+ uint32_t current_dev;
+ POOLMEM *content;
+ uint32_t content_len;
+ uint32_t acl_nr_errors;
+ uint32_t xattr_nr_errors;
+ const int *acl_streams;
+ const int *default_acl_streams;
+ const int *xattr_streams;
+ const char **xattr_skiplist;
+ const char **xattr_acl_skiplist;
+
+ void init();
+
+ /**
+ * Perform OS specyfic ACL backup.
+ * in:
+ * jcr - Job Control Record
+ * ff_pkt - file to backup information rector
+ * out:
+ * bRC_XACL_ok - backup performed without problems
+ * any other - some error ocurred
+ */
+ virtual bRC_XACL os_backup_acl (JCR *jcr, FF_PKT *ff_pkt){return bRC_XACL_fatal;};
+
+ /**
+ * Perform OS specyfic ACL restore. Runtime is called only when stream is supported by OS.
+ * in:
+ * jcr - Job Control Record
+ * ff_pkt - file to backup information rector
+ * out:
+ * bRC_XACL_ok - backup performed without problems
+ * any other - some error ocurred
+ */
+ virtual bRC_XACL os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length){return bRC_XACL_fatal;};
+
+ /**
+ * Perform OS specyfic XATTR backup.
+ *
+ * in:
+ * jcr - Job Control Record
+ * ff_pkt - file to backup control package
+ * out:
+ * bRC_XACL_ok - xattr backup ok or no xattr to backup found
+ * bRC_XACL_error/fatal - an error or fatal error occurred
+ */
+ virtual bRC_XACL os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){return bRC_XACL_fatal;};
+
+ /**
+ * Perform OS specyfic XATTR restore. Runtime is called only when stream is supported by OS.
+ *
+ * in:
+ * jcr - Job Control Record
+ * stream - backup stream number
+ * content - a buffer with data to restore
+ * length - a data restore length
+ * out:
+ * bRC_XACL_ok - xattr backup ok or no xattr to backup found
+ * bRC_XACL_error/fatal - an error or fatal error occurred
+ */
+ virtual bRC_XACL os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length){return bRC_XACL_fatal;};
+
+ /**
+ * Low level OS specyfic runtime to get ACL data from file. The ACL data is set in internal content buffer.
+ *
+ * in:
+ * jcr - Job Control Record
+ * xacltype - the acl type to restore
+ * out:
+ * bRC_XACL_ok -
+ * bRC_XACL_error/fatal - an error or fatal error occurred
+ */
+ virtual bRC_XACL os_get_acl (JCR *jcr, XACL_type xacltype){return bRC_XACL_fatal;};
+
+ /**
+ * Low level OS specyfic runtime to set ACL data on file.
+ *
+ * in:
+ * jcr - Job Control Record
+ * xacltype - the acl type to restore
+ * content - a buffer with data to restore
+ * length - a data restore length
+ * out:
+ * bRC_XACL_ok -
+ * bRC_XACL_error/fatal - an error or fatal error occurred
+ */
+ virtual bRC_XACL os_set_acl (JCR *jcr, XACL_type xacltype, char *content, uint32_t length){return bRC_XACL_fatal;};
+
+ /**
+ * Returns a list of xattr names in newly allocated pool memory and a length of the allocated buffer.
+ * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
+ * when not needed. The list of xattr names is returned as an unordered array of NULL terminated
+ * character strings (attribute names are separated by NULL characters), like this:
+ * user.name1\0system.name1\0user.name2\0
+ * The format of the list is based on standard "llistxattr" function call.
+ * TODO: change the format of the list from an array of NULL terminated strings into an alist of structures.
+ *
+ * in:
+ * jcr - Job Control Record
+ * xlen - non NULL pointer to the uint32_t variable for storing a length of the xattr names list
+ * pxlist - non NULL pointer to the char* variable for allocating a memoty data for xattr names list
+ * out:
+ * bRC_XACL_ok - we've got a xattr data to backup
+ * bRC_XACL_skip - no xattr data available, no fatal error, skip rest of the runtime
+ * bRC_XACL_fatal - when required buffers are unallocated
+ * bRC_XACL_error - in case of any error
+ */
+ virtual bRC_XACL os_get_xattr_names (JCR *jcr, POOLMEM ** pxlist, uint32_t * xlen){return bRC_XACL_fatal;};
+
+ /**
+ * Returns a value of the requested attribute name and a length of the allocated buffer.
+ * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
+ * when not needed.
+ *
+ * in:
+ * jcr - Job Control Record
+ * name - a name of the extended attribute
+ * pvalue - the pointer for the buffer with value - it is allocated by function and should be freed when no needed
+ * plen - the pointer for the length of the allocated buffer
+ *
+ * out:
+ * pxlist - the atributes list
+ * bRC_XACL_ok - we've got a xattr data which could be empty when xlen=0
+ * bRC_XACL_skip - no xattr data available, no fatal error, skip rest of the runtime
+ * bRC_XACL_error - error getting an attribute
+ * bRC_XACL_fatal - required buffers are unallocated
+ */
+ virtual bRC_XACL os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen){return bRC_XACL_fatal;};
+
+ /**
+ * Low level OS specyfic runtime to set extended attribute on file
+ *
+ * in:
+ * jcr - Job Control Record
+ * xattr - the struct with attribute/value to set
+ *
+ * out:
+ * bRC_XACL_ok - setting the attribute was ok
+ * bRC_XACL_error - error during extattribute set
+ * bRC_XACL_fatal - required buffers are unallocated
+ */
+ virtual bRC_XACL os_set_xattr (JCR *jcr, XACL_xattr *xattr){return bRC_XACL_fatal;};
+
+ void inc_acl_errors(){ acl_nr_errors++;};
+ void inc_xattr_errors(){ xattr_nr_errors++;};
+ bRC_XACL check_dev (JCR *jcr);
+ void check_dev (JCR *jcr, uint32_t dev);
+
+public:
+ XACL ();
+ virtual ~XACL();
+
+ /* enable/disable functionality */
+ void enable_acl();
+ void disable_acl();
+ void enable_xattr();
+ void disable_xattr();
+
+ /*
+ * public methods used outside the class or derivatives
+ */
+ bRC_XACL backup_acl (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL restore_acl (JCR *jcr, int stream, char *content, uint32_t content_length);
+ bRC_XACL backup_xattr (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL restore_xattr (JCR *jcr, int stream, char *content, uint32_t content_length);
+
+ /* utility functions */
+ inline uint32_t get_acl_nr_errors(){ return acl_nr_errors;};
+ inline uint32_t get_xattr_nr_errors(){ return xattr_nr_errors;};
+ void set_acl_streams (const int *pacl, const int *pacl_def);
+ void set_xattr_streams (const int *pxattr);
+ void set_xattr_skiplists (const char **pxattr, const char **pxattr_acl);
+ inline void clear_flag (uint32_t flag){ flags &= ~flag;};
+ inline void set_flag (uint32_t flag){ flags |= flag;};
+ POOLMEM * set_content (char *text);
+ POOLMEM * set_content(char *data, int len);
+ inline POOLMEM * get_content (void){ return content;};
+ inline uint32_t get_content_size (void){ return sizeof_pool_memory(content);};
+ inline uint32_t get_content_len (void){ return content_len;};
+ bool check_xattr_skiplists (JCR *jcr, FF_PKT *ff_pkt, char * name);
+
+ /* sending data to the storage */
+ bRC_XACL send_acl_stream (JCR *jcr, int stream);
+ bRC_XACL send_xattr_stream (JCR *jcr, int stream);
+
+ /* serialize / unserialize stream */
+ bRC_XACL unserialize_xattr_stream(JCR *jcr, char *content, uint32_t length, alist *list);
+ bRC_XACL serialize_xattr_stream(JCR *jcr, uint32_t len, alist *list);
+
+ /* generic functions */
+ bRC_XACL generic_backup_acl (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL generic_restore_acl (JCR *jcr, int stream);
+ bRC_XACL afs_backup_acl (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL afs_restore_acl (JCR *jcr, int stream);
+ bRC_XACL generic_backup_xattr (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL generic_restore_xattr (JCR *jcr, int stream);
+};
+
+void *new_xacl();
+
+#endif /* __BXACL_H_ */
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+/**
+ * Major refactoring of ACL and XATTR code written by:
+ *
+ * Radosław Korzeniewski, MMXVI
+ * radoslaw@korzeniewski.net, radekk@inteos.pl
+ * Inteos Sp. z o.o. http://www.inteos.pl/
+ *
+ */
+
+#include "bacula.h"
+#include "filed.h"
+#include "xacl_freebsd.h"
+
+#if defined(HAVE_FREEBSD_OS)
+/*
+ * Define the supported ACL streams for this OS
+ */
+static const int os_acl_streams[] = {
+ STREAM_XACL_FREEBSD_ACCESS,
+ STREAM_XACL_FREEBSD_NFS4,
+ 0
+};
+
+static const int os_default_acl_streams[] = {
+ STREAM_XACL_FREEBSD_DEFAULT,
+ 0
+};
+
+/*
+ * Define the supported XATTR streams for this OS
+ */
+static const int os_xattr_streams[] = {
+ STREAM_XACL_FREEBSD_XATTR,
+ 0
+};
+
+static const int os_xattr_namespaces[] = {
+ EXTATTR_NAMESPACE_USER,
+ EXTATTR_NAMESPACE_SYSTEM,
+ -1
+};
+
+static const char *os_xattr_acl_skiplist[] = {
+ "system.posix1e.acl_access",
+ "system.posix1e.acl_default",
+ "system.nfs4.acl",
+ NULL
+};
+
+static const char *os_xattr_skiplist[] = {
+ NULL
+};
+
+/*
+ * OS Specyfic constructor
+ */
+XACL_FreeBSD::XACL_FreeBSD(){
+
+ set_acl_streams(os_acl_streams, os_default_acl_streams);
+ set_xattr_streams(os_xattr_streams);
+ set_xattr_skiplists(os_xattr_skiplist, os_xattr_acl_skiplist);
+};
+
+/*
+ * Translates Bacula internal acl representation into
+ * acl type
+ *
+ * in:
+ * xacltype - internal Bacula acl type (XACL_type)
+ * out:
+ * acl_type_t - os dependent acl type
+ * when failed - ACL_TYPE_NONE is returned
+ */
+acl_type_t XACL_FreeBSD::get_acltype(XACL_type xacltype){
+
+ acl_type_t acltype;
+
+ switch (xacltype){
+#ifdef HAVE_ACL_TYPE_NFS4
+ case XACL_TYPE_NFS4:
+ acltype = ACL_TYPE_NFS4;
+ break;
+#endif
+ case XACL_TYPE_ACCESS:
+ acltype = ACL_TYPE_ACCESS;
+ break;
+ case XACL_TYPE_DEFAULT:
+ acltype = ACL_TYPE_DEFAULT;
+ break;
+ default:
+ /*
+ * sanity check for acl's not supported by OS
+ */
+ acltype = (acl_type_t)ACL_TYPE_NONE;
+ break;
+ }
+ return acltype;
+};
+
+/*
+ * Counts a number of acl entries
+ *
+ * in:
+ * acl - acl object
+ * out:
+ * int - number of entries in acl object
+ * when no acl entry available or any error then return zero '0'
+ */
+int XACL_FreeBSD::acl_nrentries(acl_t acl){
+
+ int nr = 0;
+ acl_entry_t aclentry;
+ int rc;
+
+ rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &aclentry);
+ while (rc == 1){
+ nr++;
+ rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &aclentry);
+ }
+
+ return nr;
+};
+
+/*
+ * Checks if acl is simple.
+ *
+ * acl is simple if it has only the following entries:
+ * "user::",
+ * "group::",
+ * "other::"
+ *
+ * in:
+ * acl - acl object
+ * out:
+ * true - when acl object is simple
+ * false - when acl object is not simple
+ */
+bool XACL_FreeBSD::acl_issimple(acl_t acl){
+
+ acl_entry_t aclentry;
+ acl_tag_t acltag;
+ int rc;
+
+ rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &aclentry);
+ while (rc == 1){
+ if (acl_get_tag_type(aclentry, &acltag) < 0){
+ return true;
+ }
+ /*
+ * Check for ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER to find out.
+ */
+ if (acltag != ACL_USER_OBJ &&
+ acltag != ACL_GROUP_OBJ &&
+ acltag != ACL_OTHER){
+ return false;
+ }
+ rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &aclentry);
+ }
+ return true;
+};
+
+/*
+ * Checks if ACL's are available for a specified file
+ *
+ * in:
+ * jcr - Job Control Record
+ * name - specifies the system variable to be queried
+ * out:
+ * bRC_XACL_ok - check successful, lets setup xacltype variable
+ * bRC_XACL_error - in case of error
+ * bRC_XACL_skip - you should skip all other routine
+ * bRC_XACL_cont - you need to continue your routine
+ */
+bRC_XACL XACL_FreeBSD::check_xacltype (JCR *jcr, int name){
+
+ int aclrc = 0;
+
+ aclrc = pathconf(jcr->last_fname, name);
+ switch (aclrc){
+ case -1: {
+ /* some error check why */
+ berrno be;
+ if (errno == ENOENT){
+ /* file does not exist skip it */
+ return bRC_XACL_skip;
+ } else {
+ Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "pathconf error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ }
+ case 0:
+ /* continue the routine */
+ return bRC_XACL_cont;
+ default:
+ break;
+ }
+ return bRC_XACL_ok;
+};
+
+/*
+ * Perform OS specyfic ACL backup
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_FreeBSD::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
+
+ bRC_XACL rc;
+ XACL_type xacltype = XACL_TYPE_NONE;
+
+#if defined(_PC_ACL_NFS4)
+ /*
+ * Check if filesystem supports NFS4 acls.
+ */
+ rc = check_xacltype(jcr, _PC_ACL_NFS4);
+ switch (rc){
+ case bRC_XACL_ok:
+ xacltype = XACL_TYPE_NFS4;
+ break;
+ case bRC_XACL_skip:
+ return bRC_XACL_ok;
+ case bRC_XACL_cont:
+ break;
+ default:
+ /* errors */
+ return rc;
+ }
+#endif
+ if (xacltype == XACL_TYPE_NONE){
+ /*
+ * Check if filesystem supports POSIX acls.
+ */
+ rc = check_xacltype(jcr, _PC_ACL_EXTENDED);
+ switch (rc){
+ case bRC_XACL_ok:
+ xacltype = XACL_TYPE_ACCESS;
+ break;
+ case bRC_XACL_skip:
+ return bRC_XACL_ok;
+ case bRC_XACL_cont:
+ break;
+ default:
+ /* errors */
+ return rc;
+ }
+ }
+
+ /* no ACL's available for file, so skip this filesystem */
+ if (xacltype == XACL_TYPE_NONE){
+ clear_flag(XACL_FLAG_NATIVE);
+ /*
+ * it is a bit of hardcore to clear a poolmemory with a NULL pointer,
+ * but it is working, hehe :)
+ * you may ask why it is working? it is simple, a pm_strcpy function is handling
+ * a null pointer with a substitiution of empty string.
+ */
+ set_content(NULL);
+ return bRC_XACL_ok;
+ }
+
+ switch (xacltype){
+ case XACL_TYPE_NFS4:
+ /*
+ * Read NFS4 ACLs
+ */
+ if (os_get_acl(jcr, XACL_TYPE_NFS4) == bRC_XACL_fatal)
+ return bRC_XACL_fatal;
+
+ if (get_content_len() > 0){
+ if (send_acl_stream(jcr, STREAM_XACL_FREEBSD_NFS4) == bRC_XACL_fatal)
+ return bRC_XACL_fatal;
+ }
+ break;
+ case XACL_TYPE_ACCESS:
+ /*
+ * Read access ACLs
+ */
+ if (os_get_acl(jcr, XACL_TYPE_ACCESS) == bRC_XACL_fatal)
+ return bRC_XACL_fatal;
+
+ if (get_content_len() > 0){
+ if (send_acl_stream(jcr, STREAM_XACL_FREEBSD_ACCESS) == bRC_XACL_fatal)
+ return bRC_XACL_fatal;
+ }
+
+ /*
+ * Directories can have default ACLs too
+ */
+ if (ff_pkt->type == FT_DIREND){
+ if (os_get_acl(jcr, XACL_TYPE_DEFAULT) == bRC_XACL_fatal)
+ return bRC_XACL_fatal;
+ if (get_content_len() > 0){
+ if (send_acl_stream(jcr, STREAM_XACL_FREEBSD_DEFAULT) == bRC_XACL_fatal)
+ return bRC_XACL_fatal;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return bRC_XACL_ok;
+};
+
+/*
+ * Perform OS specyfic ACL restore
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_FreeBSD::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length){
+
+ int aclrc = 0;
+ const char *acl_type_name;
+
+ switch (stream){
+ case STREAM_UNIX_ACCESS_ACL:
+ case STREAM_XACL_FREEBSD_ACCESS:
+ case STREAM_UNIX_DEFAULT_ACL:
+ case STREAM_XACL_FREEBSD_DEFAULT:
+ aclrc = pathconf(jcr->last_fname, _PC_ACL_EXTENDED);
+ acl_type_name = "POSIX";
+ break;
+ case STREAM_XACL_FREEBSD_NFS4:
+#if defined(_PC_ACL_NFS4)
+ aclrc = pathconf(jcr->last_fname, _PC_ACL_NFS4);
+#endif
+ acl_type_name = "NFS4";
+ break;
+ default:
+ acl_type_name = "unknown";
+ break;
+ }
+
+ switch (aclrc){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ return bRC_XACL_ok;
+ default:
+ Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ }
+ case 0:
+ clear_flag(XACL_FLAG_NATIVE);
+ Mmsg2(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without %s acl support\n"), jcr->last_fname, acl_type_name);
+ return bRC_XACL_error;
+ default:
+ break;
+ }
+
+ switch (stream){
+ case STREAM_UNIX_ACCESS_ACL:
+ case STREAM_XACL_FREEBSD_ACCESS:
+ return os_set_acl(jcr, XACL_TYPE_ACCESS, content, length);
+ case STREAM_UNIX_DEFAULT_ACL:
+ case STREAM_XACL_FREEBSD_DEFAULT:
+ return os_set_acl(jcr, XACL_TYPE_DEFAULT, content, length);
+ case STREAM_XACL_FREEBSD_NFS4:
+ return os_set_acl(jcr, XACL_TYPE_NFS4, content, length);
+ default:
+ break;
+ }
+ return bRC_XACL_error;
+};
+
+/*
+ * Perform OS specyfic extended attribute backup
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_FreeBSD::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
+
+ bRC_XACL rc;
+ POOLMEM *xlist;
+ uint32_t xlen;
+ char *name;
+ uint32_t name_len;
+ POOLMEM *value;
+ uint32_t value_len;
+ POOLMEM *name_gen;
+ uint32_t name_gen_len;
+ char * namespace_str;
+ int namespace_len;
+ bool skip;
+ alist *xattr_list = NULL;
+ int xattr_count = 0;
+ uint32_t len = 0;
+ XACL_xattr *xattr;
+ int a;
+
+ for (a = 0; os_xattr_namespaces[a] != -1; a++){ // loop through all available namespaces
+ /* xlist is allocated as POOLMEM by os_get_xattr_names */
+ rc = os_get_xattr_names(jcr, os_xattr_namespaces[a], &xlist, &xlen);
+ switch (rc){
+ case bRC_XACL_ok:
+ /* it's ok, so go further */
+ break;
+ case bRC_XACL_skip:
+ case bRC_XACL_cont:
+ /* no xattr available, so skip rest of it */
+ return bRC_XACL_ok;
+ default:
+ return rc;
+ }
+
+ /* get a string representation of the namespace */
+ if (extattr_namespace_to_string(os_xattr_namespaces[a], &namespace_str) != 0){
+ Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"), os_xattr_namespaces[a], jcr->last_fname);
+ Dmsg2(100, "Failed to convert %d into namespace on file \"%s\"\n", os_xattr_namespaces[a], jcr->last_fname);
+ goto bail_out;
+ }
+ namespace_len = strlen(namespace_str);
+
+ /* follow the list of xattr names and get the values */
+ for (name = xlist; (name - xlist) + 1 < xlen; name = strchr(name, '\0') + 1){
+ name_len = strlen(name);
+ name_gen = get_pool_memory(PM_FNAME);
+ name_gen = check_pool_memory_size(name_gen, name_len + namespace_len + 2);
+ bsnprintf(name_gen, name_len + namespace_len + 2, "%s.%s", namespace_str, name);
+ name_gen_len = strlen(name_gen);
+
+ skip = check_xattr_skiplists(jcr, ff_pkt, name_gen);
+ if (skip || name_len == 0){
+ Dmsg1(100, "Skipping xattr named %s\n", name_gen);
+ continue;
+ }
+
+ /* value is allocated as POOLMEM by os_get_xattr_value */
+ rc = os_get_xattr_value(jcr, os_xattr_namespaces[a], name, &value, &value_len);
+ switch (rc){
+ case bRC_XACL_ok:
+ /* it's ok, so go further */
+ break;
+ case bRC_XACL_skip:
+ /* no xattr available, so skip rest of it */
+ rc = bRC_XACL_ok;
+ goto bail_out;
+ default:
+ /* error / fatal */
+ goto bail_out;
+ }
+
+ /*
+ * we have a name of the extended attribute in the name variable
+ * and value of the extended attribute in the value variable
+ * so we need to build a list
+ */
+ xattr = (XACL_xattr*)malloc(sizeof(XACL_xattr));
+ xattr->name_len = name_gen_len;
+ xattr->name = name_gen;
+ xattr->value_len = value_len;
+ xattr->value = value;
+ /* magic name_len name value_len value */
+ len += sizeof(uint32_t) + sizeof(uint32_t) + name_gen_len + sizeof(uint32_t) + value_len;
+
+ if (xattr_list == NULL){
+ xattr_list = New(alist(10, not_owned_by_alist));
+ }
+ xattr_list->append(xattr);
+ xattr_count++;
+ }
+ if (xattr_count > 0){
+ /* serialize the stream */
+ rc = serialize_xattr_stream(jcr, len, xattr_list);
+ if (rc != bRC_XACL_ok){
+ Mmsg(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"), jcr->last_fname);
+ Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n", jcr->last_fname);
+ goto bail_out;
+ } else {
+ /* send data to SD */
+ rc = send_xattr_stream(jcr, STREAM_XACL_FREEBSD_XATTR);
+ }
+ } else {
+ rc = bRC_XACL_ok;
+ }
+ }
+bail_out:
+ /* free allocated data */
+ if (xattr_list != NULL){
+ foreach_alist(xattr, xattr_list){
+ if (xattr == NULL){
+ break;
+ }
+ if (xattr->name){
+ free_pool_memory(name_gen);
+ }
+ if (xattr->value){
+ free(xattr->value);
+ }
+ free(xattr);
+ }
+ delete xattr_list;
+ }
+ if (xlist != NULL){
+ free(xlist);
+ }
+
+ return rc;
+};
+
+/*
+ * Perform OS specyfic XATTR restore. Runtime is called only when stream is supported by OS.
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_FreeBSD::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length){
+ return generic_restore_xattr(jcr, stream);
+};
+
+/*
+ * Low level OS specyfic runtime to get ACL data from file. The ACL data is set in internal content buffer
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_FreeBSD::os_get_acl(JCR *jcr, XACL_type xacltype){
+
+ acl_t acl;
+ acl_type_t acltype;
+ char *acltext;
+ bRC_XACL rc = bRC_XACL_ok;
+
+ acltype = get_acltype(xacltype);
+ acl = acl_get_file(jcr->last_fname, acltype);
+
+ if (acl){
+ Dmsg1(400, "OS_ACL read from file: %s\n",jcr->last_fname);
+ if (acl_nrentries(acl) == 0){
+ goto bail_out;
+ }
+
+ /* check for fimple ACL which correspond to standard permissions only */
+ if (xacltype == XACL_TYPE_ACCESS && acl_issimple(acl)){
+ goto bail_out;
+ }
+
+#if defined(_PC_ACL_NFS4)
+ if (xacltype == XACL_TYPE_NFS4){
+ int trivial;
+ if (acl_is_trivial_np(acl, &trivial) == 0){
+ if (trivial == 1){
+ goto bail_out;
+ }
+ }
+ }
+#endif
+
+ if ((acltext = acl_to_text(acl, NULL)) != NULL){
+ set_content(acltext);
+ acl_free(acl);
+ acl_free(acltext);
+ return bRC_XACL_ok;
+ }
+
+ berrno be;
+
+ Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "acl_to_text error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+
+ rc = bRC_XACL_error;
+
+ } else {
+ berrno be;
+
+ switch (errno){
+ case EOPNOTSUPP:
+ /* fs does not support acl, skip it */
+ Dmsg0(400, "Wow, ACL is not supported on this filesystem\n");
+ clear_flag(XACL_FLAG_NATIVE);
+ break;
+ case ENOENT:
+ break;
+ default:
+ /* Some real error */
+ Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "acl_get_file error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ rc = bRC_XACL_error;
+ break;
+ }
+ }
+
+bail_out:
+ if (acl){
+ acl_free(acl);
+ }
+ /*
+ * it is a bit of hardcore to clear a poolmemory with a NULL pointer,
+ * but it is working, hehe :)
+ * you may ask why it is working? it is simple, a pm_strcpy function is handling
+ * a null pointer with a substitiution of empty string.
+ */
+ set_content(NULL);
+ return rc;
+};
+
+/*
+ * Low level OS specyfic runtime to set ACL data on file
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_FreeBSD::os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length){
+
+ acl_t acl;
+ acl_type_t acltype;
+
+ acltype = get_acltype(xacltype);
+ if (acltype == ACL_TYPE_DEFAULT && length == 0){
+ /* delete ACl from file when no acl data available for default acl's */
+ if (acl_delete_def_file(jcr->last_fname) == 0){
+ return bRC_XACL_ok;
+ }
+
+ berrno be;
+ switch (errno){
+ case ENOENT:
+ return bRC_XACL_ok;
+ case ENOTSUP:
+ /*
+ * If the filesystem reports it doesn't support acl's we clear the
+ * XACL_FLAG_NATIVE flag so we skip ACL restores on all other files
+ * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
+ * when we change from one filesystem to an other.
+ */
+ clear_flag(XACL_FLAG_NATIVE);
+ Mmsg(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"), jcr->last_fname);
+ return bRC_XACL_error;
+ default:
+ Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ }
+
+ acl = acl_from_text(content);
+ if (acl == NULL){
+ berrno be;
+
+ Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+
+ /*
+ * Restore the ACLs, but don't complain about links which really should
+ * not have attributes, and the file it is linked to may not yet be restored.
+ * This is only true for the old acl streams as in the new implementation we
+ * don't save acls of symlinks (which cannot have acls anyhow)
+ */
+ if (acl_set_file(jcr->last_fname, acltype, acl) != 0 && jcr->last_type != FT_LNK){
+ berrno be;
+ switch (errno){
+ case ENOENT:
+ acl_free(acl);
+ return bRC_XACL_ok;
+ case ENOTSUP:
+ /*
+ * If the filesystem reports it doesn't support ACLs we clear the
+ * XACL_FLAG_NATIVE flag so we skip ACL restores on all other files
+ * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
+ * when we change from one filesystem to an other.
+ */
+ clear_flag(XACL_FLAG_NATIVE);
+ Mmsg(jcr->errmsg, _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"), jcr->last_fname);
+ Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n", content, jcr->last_fname);
+ acl_free(acl);
+ return bRC_XACL_error;
+ default:
+ Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
+ acl_free(acl);
+ return bRC_XACL_error;
+ }
+ }
+ acl_free(acl);
+ return bRC_XACL_ok;
+};
+
+/*
+ * Return a list of xattr names in newly allocated pool memory and a length of the allocated buffer.
+ * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
+ * when not needed.
+ *
+ * in/out - check API at xacl.h
+ *
+ * As a FreeBSD uses a different attributes name schema/format then this method is a very different
+ * from a standard generic method because it uses a namespace (ns) value for os dependent optimization.
+ */
+bRC_XACL XACL_FreeBSD::os_get_xattr_names (JCR *jcr, int ns, POOLMEM ** pxlist, uint32_t * xlen){
+
+ int len;
+ POOLMEM * list;
+ int a;
+ int stra;
+ POOLMEM * genlist;
+
+ /* check input data */
+ if (jcr == NULL || xlen == NULL || pxlist == NULL){
+ return bRC_XACL_inval;
+ }
+ /* get the length of the extended attributes */
+ len = extattr_list_link(jcr->last_fname, ns, NULL, 0);
+ switch (len){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it */
+ return bRC_XACL_skip;
+ case EOPNOTSUPP:
+ /* no xattr supported on filesystem, clear a flag and skip it */
+ clear_flag(XACL_FLAG_NATIVE);
+ set_content(NULL);
+ return bRC_XACL_skip;
+ case EPERM:
+ if (ns == EXTATTR_NAMESPACE_SYSTEM){
+ return bRC_XACL_cont;
+ } /* else show error */
+ default:
+ Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ break;
+ }
+ case 0:
+ /* xattr available but empty, skip it */
+ return bRC_XACL_skip;
+ default:
+ break;
+ }
+
+ /*
+ * allocate memory for the extented attribute list
+ * default size is a 4k for PM_BSOCK, which should be sufficient on almost all
+ * Linux system where xattrs a limited in size to single filesystem block ~4kB
+ * so we need to check required size
+ */
+ list = get_pool_memory(PM_BSOCK);
+ list = check_pool_memory_size(list, len + 1);
+ memset(list, 0, len + 1);
+
+ /* get the list of extended attributes names for a file */
+ len = extattr_list_link(jcr->last_fname, ns, list, len);
+ switch (len){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it, first release allocated memory */
+ free_pool_memory(list);
+ return bRC_XACL_skip;
+ case EPERM:
+ if (ns == EXTATTR_NAMESPACE_SYSTEM){
+ return bRC_XACL_cont;
+ } /* else show error */
+ default:
+ Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "extattr_list_link error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ free_pool_memory(list);
+ return bRC_XACL_error;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ /* convert FreeBSD list type to the generic one */
+ genlist = get_pool_memory(PM_BSOCK);
+ genlist = check_pool_memory_size(genlist, len + 1);
+ memset(genlist, 0, len + 1);
+ for (a = 0; a < len; a += list[a] + 1){
+ stra = list[a];
+ memcpy(genlist + a, list + a + 1, stra);
+ genlist[a + stra] = '\0';
+ }
+ free_pool_memory(list);
+ /* setup return data */
+ *pxlist = genlist;
+ *xlen = len;
+ return bRC_XACL_ok;
+};
+
+/*
+ * Return a value of the requested attribute name and a length of the allocated buffer.
+ * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
+ * when not needed.
+ *
+ * in/out - check API at xacl.h
+ *
+ * As a FreeBSD uses a different attributes name schema/format then this method is a very different
+ * from a standard generic method because it uses a namespace (ns) value for os dependent optimization.
+ */
+bRC_XACL XACL_FreeBSD::os_get_xattr_value (JCR *jcr, int ns, char * name, char ** pvalue, uint32_t * plen){
+
+ int len;
+ POOLMEM * value;
+
+ /* check input data */
+ if (jcr == NULL || name == NULL || plen == NULL || pvalue == NULL){
+ return bRC_XACL_inval;
+ }
+ /* get the length of the value for extended attribute */
+ len = extattr_get_link(jcr->last_fname, ns, name, NULL, 0);
+ switch (len){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it */
+ return bRC_XACL_skip;
+ default:
+ /* XXX: what about ENOATTR error value? */
+ Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (len > 0){
+ /*
+ * allocate memory for the extented attribute value
+ * default size is a 256B for PM_MESSAGE, so we need to check required size
+ */
+ value = get_pool_memory(PM_MESSAGE);
+ value = check_pool_memory_size(value, len + 1);
+ memset(value, 0, len + 1);
+ /* value is not empty, get a data */
+ len = extattr_get_link(jcr->last_fname, ns, name, value, len);
+ switch (len){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it, first release allocated memory */
+ free_pool_memory(value);
+ return bRC_XACL_skip;
+ default:
+ Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "extattr_get_link error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ free_pool_memory(value);
+ return bRC_XACL_error;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ /* ensure a value is nul terminated */
+ value[len] = '\0';
+ } else {
+ /* empty value */
+ value = NULL;
+ len = 0;
+ }
+ /* setup return data */
+ *pvalue = value;
+ *plen = len;
+ return bRC_XACL_ok;
+};
+
+/*
+ * Low level OS specyfic runtime to set extended attribute on file
+ *
+ * in/out - check API at xacl.h
+ *
+ * xattr->name should be in '<namespace>.<name>' format which
+ * function handle without problem, otherwise it returns an error
+ * TODO: it is possible to handle a different attributes name format
+ * for os portability where default namespace 'user' can be used
+ */
+bRC_XACL XACL_FreeBSD::os_set_xattr (JCR *jcr, XACL_xattr *xattr){
+
+ char * name;
+ char * nspace;
+ int ns;
+ int rc;
+
+ /* check input data */
+ if (jcr == NULL || xattr == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* search for attribute namespace which is distinguished from attribute name by a dot '.' character */
+ if ((name = strchr(xattr->name, '.')) == (char *)NULL){
+ Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"), xattr->name, jcr->last_fname);
+ Dmsg2(100, "Failed to split %s into namespace and name part on file \"%s\"\n", xattr->name, jcr->last_fname);
+ return bRC_XACL_error;
+ }
+
+ /* split namespace and name of the attribute */
+ nspace = xattr->name;
+ *name++ = '\0';
+
+ /* check if namespace is valid on this system */
+ if (extattr_string_to_namespace(nspace, &ns) != 0){
+ Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"), nspace, jcr->last_fname);
+ Dmsg2(100, "Failed to convert %s into namespace on file \"%s\"\n", nspace, jcr->last_fname);
+ return bRC_XACL_error;
+ }
+
+ /* set extattr on file */
+ rc = extattr_set_link(jcr->last_fname, ns, name, xattr->value, xattr->value_len);
+ if (rc < 0 || rc != (int)xattr->value_len){
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ break;
+ default:
+ Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "extattr_set_link error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ }
+ return bRC_XACL_ok;
+};
+
+#endif /* HAVE_FREEBSD_OS */
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+/**
+ * Major refactoring of ACL and XATTR code written by:
+ *
+ * Radosław Korzeniewski, MMXVI
+ * radoslaw@korzeniewski.net, radekk@inteos.pl
+ * Inteos Sp. z o.o. http://www.inteos.pl/
+ *
+ */
+
+#ifndef __XACL_FreeBSD_H_
+#define __XACL_FreeBSD_H_
+
+#if defined(HAVE_FREEBSD_OS)
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#else
+#error "configure failed to detect availability of sys/acl.h"
+#endif
+
+#if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
+ (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
+ (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
+ !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
+ !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
+#error "Missing full support for the extattr functions."
+#endif
+
+#ifdef HAVE_SYS_EXTATTR_H
+#include <sys/types.h>
+#include <sys/extattr.h>
+#else
+#error "Missing sys/extattr.h header file"
+#endif
+
+#ifdef HAVE_LIBUTIL_H
+#include <libutil.h>
+#endif
+
+#if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
+#define extattr_get_link extattr_get_file
+#endif
+#if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
+#define extattr_set_link extattr_set_file
+#endif
+#if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
+#define extattr_list_link extattr_list_file
+#endif
+
+/*
+ *
+ *
+ */
+class XACL_FreeBSD : public XACL {
+private:
+ bRC_XACL os_backup_acl (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length);
+ bRC_XACL os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length);
+ bRC_XACL os_get_acl(JCR *jcr, XACL_type xacltype);
+ bRC_XACL os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length);
+ bRC_XACL os_get_xattr_names (JCR *jcr, const int ns, POOLMEM **list, uint32_t *length);
+ bRC_XACL os_get_xattr_value (JCR *jcr, const int ns, char * name, char ** pvalue, uint32_t * plen);
+ bRC_XACL os_set_xattr (JCR *jcr, XACL_xattr *xattr);
+ /* requires acl.h available */
+ bool acl_issimple(acl_t acl);
+ acl_type_t get_acltype(XACL_type xacltype);
+ int acl_nrentries(acl_t acl);
+ bRC_XACL check_xacltype (JCR *jcr, int name);
+public:
+ XACL_FreeBSD ();
+};
+
+#endif /* HAVE_FREEBSD_OS */
+
+#endif /* __XACL_FreeBSD_H_ */
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+/**
+ * Major refactoring of ACL and XATTR code written by:
+ *
+ * Radosław Korzeniewski, MMXVI
+ * radoslaw@korzeniewski.net, radekk@inteos.pl
+ * Inteos Sp. z o.o. http://www.inteos.pl/
+ *
+ */
+
+#include "bacula.h"
+#include "filed.h"
+#include "xacl_linux.h"
+
+#if defined(HAVE_LINUX_OS)
+/*
+ * Define the supported ACL streams for this OS
+ */
+static const int os_acl_streams[] = {
+ STREAM_XACL_LINUX_ACCESS,
+ 0
+};
+
+static const int os_default_acl_streams[] = {
+ STREAM_XACL_LINUX_DEFAULT,
+ 0
+};
+
+/*
+ * Define the supported XATTR streams for this OS
+ */
+static const int os_xattr_streams[] = {
+ STREAM_XACL_LINUX_XATTR,
+ 0
+};
+
+static const char *os_xattr_acl_skiplist[] = {
+ "system.posix_acl_access",
+ "system.posix_acl_default",
+ NULL
+};
+
+static const char *os_xattr_skiplist[] = {
+ NULL
+};
+
+/*
+ * OS Specyfic constructor
+ */
+XACL_Linux::XACL_Linux(){
+ set_acl_streams(os_acl_streams, os_default_acl_streams);
+ set_xattr_streams(os_xattr_streams);
+ set_xattr_skiplists(os_xattr_skiplist, os_xattr_acl_skiplist);
+};
+
+/*
+ * Translates Bacula internal acl representation into
+ * acl type
+ *
+ * in:
+ * xacltype - internal Bacula acl type (XACL_type)
+ * out:
+ * acl_type_t - os dependent acl type
+ * when failed - ACL_TYPE_NONE is returned
+ */
+acl_type_t XACL_Linux::get_acltype(XACL_type xacltype){
+
+ acl_type_t acltype;
+
+ switch (xacltype){
+ case XACL_TYPE_ACCESS:
+ acltype = ACL_TYPE_ACCESS;
+ break;
+ case XACL_TYPE_DEFAULT:
+ acltype = ACL_TYPE_DEFAULT;
+ break;
+ default:
+ /*
+ * sanity check for acl's not supported by OS
+ */
+ acltype = (acl_type_t)ACL_TYPE_NONE;
+ break;
+ }
+ return acltype;
+};
+
+/*
+ * Counts a number of acl entries
+ *
+ * in:
+ * acl - acl object
+ * out:
+ * int - number of entries in acl object
+ * when no acl entry available or any error then return zero '0'
+ */
+int XACL_Linux::acl_nrentries(acl_t acl){
+
+ int nr = 0;
+ acl_entry_t aclentry;
+ int rc;
+
+ rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &aclentry);
+ while (rc == 1){
+ nr++;
+ rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &aclentry);
+ }
+
+ return nr;
+};
+
+/*
+ * Checks if acl is simple.
+ *
+ * acl is simple if it has only the following entries:
+ * "user::",
+ * "group::",
+ * "other::"
+ *
+ * in:
+ * acl - acl object
+ * out:
+ * true - when acl object is simple
+ * false - when acl object is not simple
+ */
+bool XACL_Linux::acl_issimple(acl_t acl){
+
+ acl_entry_t aclentry;
+ acl_tag_t acltag;
+ int rc;
+
+ rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &aclentry);
+ while (rc == 1){
+ if (acl_get_tag_type(aclentry, &acltag) < 0){
+ return true;
+ }
+ /*
+ * Check for ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER to find out.
+ */
+ if (acltag != ACL_USER_OBJ &&
+ acltag != ACL_GROUP_OBJ &&
+ acltag != ACL_OTHER){
+ return false;
+ }
+ rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &aclentry);
+ }
+ return true;
+};
+
+/*
+ * Perform OS specyfic ACL backup
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Linux::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
+ return generic_backup_acl(jcr, ff_pkt);
+};
+
+/*
+ * Perform OS specyfic ACL restore
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Linux::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length){
+ return generic_restore_acl(jcr, stream);
+};
+
+/*
+ * Perform OS specyfic extended attribute backup
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Linux::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
+ return generic_backup_xattr(jcr, ff_pkt);
+};
+
+/*
+ * Perform OS specyfic XATTR restore. Runtime is called only when stream is supported by OS.
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Linux::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length){
+ return generic_restore_xattr(jcr, stream);
+};
+
+/*
+ * Low level OS specyfic runtime to get ACL data from file. The ACL data is set in internal content buffer.
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Linux::os_get_acl(JCR *jcr, XACL_type xacltype){
+
+ acl_t acl;
+ acl_type_t acltype;
+ char *acltext;
+ bRC_XACL rc = bRC_XACL_ok;
+
+ /* check input data */
+ if (jcr == NULL){
+ return bRC_XACL_inval;
+ }
+
+ acltype = get_acltype(xacltype);
+ acl = acl_get_file(jcr->last_fname, acltype);
+
+ if (acl){
+ Dmsg1(400, "OS_ACL read from file: %s\n",jcr->last_fname);
+ if (acl_nrentries(acl) == 0){
+ goto bail_out;
+ }
+
+ /* check for fimple ACL which correspond to standard permissions only */
+ if (xacltype == XACL_TYPE_ACCESS && acl_issimple(acl)){
+ goto bail_out;
+ }
+
+ if ((acltext = acl_to_text(acl, NULL)) != NULL){
+ set_content(acltext);
+ acl_free(acl);
+ acl_free(acltext);
+ return bRC_XACL_ok;
+ }
+
+ berrno be;
+
+ Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "acl_to_text error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+
+ rc = bRC_XACL_error;
+ } else {
+ berrno be;
+
+ switch (errno){
+ case EOPNOTSUPP:
+ /* fs does not support acl, skip it */
+ Dmsg0(400, "Wow, ACL is not supported on this filesystem\n");
+ clear_flag(XACL_FLAG_NATIVE);
+ break;
+ case ENOENT:
+ break;
+ default:
+ /* Some real error */
+ Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "acl_get_file error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ rc = bRC_XACL_error;
+ break;
+ }
+ }
+
+bail_out:
+ if (acl){
+ acl_free(acl);
+ }
+ /*
+ * it is a bit of hardcore to clear a poolmemory with a NULL pointer,
+ * but it is working, hehe :)
+ * you may ask why it is working? it is simple, a pm_strcpy function is handling
+ * a null pointer with a substitiution of empty string.
+ */
+ set_content(NULL);
+ return rc;
+};
+
+/*
+ * Low level OS specyfic runtime to set ACL data on file
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Linux::os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length){
+
+ acl_t acl;
+ acl_type_t acltype;
+
+ /* check input data */
+ if (jcr == NULL || content == NULL){
+ return bRC_XACL_inval;
+ }
+
+ acl = acl_from_text(content);
+ if (acl == NULL){
+ berrno be;
+
+ Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+
+ if (acl_valid(acl) != 0){
+ berrno be;
+
+ Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
+ acl_free(acl);
+ return bRC_XACL_error;
+ }
+
+ /* handle different acl types for Linux */
+ acltype = get_acltype(xacltype);
+ if (acltype == ACL_TYPE_DEFAULT && length == 0){
+ /* delete ACl from file when no acl data available for default acl's */
+ if (acl_delete_def_file(jcr->last_fname) == 0){
+ return bRC_XACL_ok;
+ }
+
+ berrno be;
+ switch (errno){
+ case ENOENT:
+ return bRC_XACL_ok;
+ case ENOTSUP:
+ /*
+ * If the filesystem reports it doesn't support acl's we clear the
+ * XACL_FLAG_NATIVE flag so we skip ACL restores on all other files
+ * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
+ * when we change from one filesystem to an other.
+ */
+ clear_flag(XACL_FLAG_NATIVE);
+ Mmsg(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": filesystem doesn't support ACLs\n"), jcr->last_fname);
+ return bRC_XACL_error;
+ default:
+ Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ }
+
+ /*
+ * Restore the ACLs, but don't complain about links which really should
+ * not have attributes, and the file it is linked to may not yet be restored.
+ * This is only true for the old acl streams as in the new implementation we
+ * don't save acls of symlinks (which cannot have acls anyhow)
+ */
+ if (acl_set_file(jcr->last_fname, acltype, acl) != 0 && jcr->last_type != FT_LNK){
+ berrno be;
+ switch (errno){
+ case ENOENT:
+ acl_free(acl);
+ return bRC_XACL_ok;
+ case ENOTSUP:
+ /*
+ * If the filesystem reports it doesn't support ACLs we clear the
+ * XACL_FLAG_NATIVE flag so we skip ACL restores on all other files
+ * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
+ * when we change from one filesystem to an other.
+ */
+ clear_flag(XACL_FLAG_NATIVE);
+ Mmsg(jcr->errmsg, _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"), jcr->last_fname);
+ Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n", content, jcr->last_fname);
+ acl_free(acl);
+ return bRC_XACL_error;
+ default:
+ Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
+ acl_free(acl);
+ return bRC_XACL_error;
+ }
+ }
+ acl_free(acl);
+ return bRC_XACL_ok;
+};
+
+/*
+ * Return a list of xattr names in newly allocated pool memory and a length of the allocated buffer.
+ * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
+ * when not needed.
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Linux::os_get_xattr_names (JCR *jcr, POOLMEM ** pxlist, uint32_t * xlen){
+
+ int len;
+ POOLMEM * list;
+
+ /* check input data */
+ if (jcr == NULL || xlen == NULL || pxlist == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* get the length of the extended attributes */
+ len = llistxattr(jcr->last_fname, NULL, 0);
+ switch (len){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it */
+ return bRC_XACL_skip;
+ case EOPNOTSUPP:
+ /* no xattr supported on filesystem, clear a flag and skip it */
+ clear_flag(XACL_FLAG_NATIVE);
+ set_content(NULL);
+ return bRC_XACL_skip;
+ default:
+ Mmsg2(jcr->errmsg, _("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 bRC_XACL_error;
+ }
+ break;
+ }
+ case 0:
+ /* xattr available but empty, skip it */
+ return bRC_XACL_skip;
+ default:
+ break;
+ }
+
+ /*
+ * allocate memory for the extented attribute list
+ * default size is a 4k for PM_BSOCK, which should be sufficient on almost all
+ * Linux system where xattrs a limited in size to single filesystem block ~4kB
+ * so we need to check required size
+ */
+ list = get_pool_memory(PM_BSOCK);
+ list = check_pool_memory_size(list, len + 1);
+ memset(list, 0, len + 1);
+
+ /* get the list of extended attributes names for a file */
+ len = llistxattr(jcr->last_fname, list, len);
+ switch (len){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it, first release allocated memory */
+ free_pool_memory(list);
+ return bRC_XACL_skip;
+ default:
+ Mmsg2(jcr->errmsg, _("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_pool_memory(list);
+ return bRC_XACL_error;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ /* ensure a list is nul terminated */
+ list[len] = '\0';
+ /* setup return data */
+ *pxlist = list;
+ *xlen = len;
+ return bRC_XACL_ok;
+};
+
+/*
+ * Return a value of the requested attribute name and a length of the allocated buffer.
+ * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
+ * when not needed.
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Linux::os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen){
+
+ int len;
+ POOLMEM * value;
+
+ /* check input data */
+ if (jcr == NULL || name == NULL || plen == NULL || pvalue == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* get the length of the value for extended attribute */
+ len = lgetxattr(jcr->last_fname, name, NULL, 0);
+ switch (len){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it */
+ return bRC_XACL_skip;
+ default:
+ /* XXX: what about ENOATTR error value? */
+ Mmsg2(jcr->errmsg, _("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());
+ return bRC_XACL_error;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (len > 0){
+ /*
+ * allocate memory for the extented attribute value
+ * default size is a 256B for PM_MESSAGE, so we need to check required size
+ */
+ value = get_pool_memory(PM_MESSAGE);
+ value = check_pool_memory_size(value, len + 1);
+ memset(value, 0, len + 1);
+ /* value is not empty, get a data */
+ len = lgetxattr(jcr->last_fname, name, value, len);
+ switch (len){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it, first release allocated memory */
+ free_pool_memory(value);
+ return bRC_XACL_skip;
+ default:
+ Mmsg2(jcr->errmsg, _("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());
+ free_pool_memory(value);
+ return bRC_XACL_error;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ /* ensure a value is nul terminated */
+ value[len] = '\0';
+ } else {
+ /* empty value */
+ value = NULL;
+ len = 0;
+ }
+ /* setup return data */
+ *pvalue = value;
+ *plen = len;
+ return bRC_XACL_ok;
+};
+
+/*
+ * Low level OS specyfic runtime to set extended attribute on file
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Linux::os_set_xattr (JCR *jcr, XACL_xattr *xattr){
+
+ /* check input data */
+ if (jcr == NULL || xattr == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* set extattr on file */
+ if (lsetxattr(jcr->last_fname, xattr->name, xattr->value, xattr->value_len, 0) != 0){
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ break;
+ case ENOTSUP:
+ /*
+ * If the filesystem reports it doesn't support XATTR we clear the
+ * XACL_FLAG_NATIVE flag so we skip XATTR restores on all other files
+ * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
+ * when we change from one filesystem to an other.
+ */
+ clear_flag(XACL_FLAG_NATIVE);
+ Mmsg(jcr->errmsg, _("setxattr error on file \"%s\": filesystem doesn't support XATTR\n"), jcr->last_fname);
+ Dmsg3(100, "setxattr error name=%s value=%s file=%s filesystem doesn't support XATTR\n", xattr->name, xattr->value, jcr->last_fname);
+ break;
+ default:
+ Mmsg2(jcr->errmsg, _("setxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "setxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ }
+ return bRC_XACL_ok;
+};
+
+#endif /* HAVE_LINUX_OS */
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+/**
+ * Major refactoring of ACL and XATTR code written by:
+ *
+ * Radosław Korzeniewski, MMXVI
+ * radoslaw@korzeniewski.net, radekk@inteos.pl
+ * Inteos Sp. z o.o. http://www.inteos.pl/
+ *
+ */
+
+#ifndef __XACL_LINUX_H_
+#define __XACL_LINUX_H_
+
+#if defined(HAVE_LINUX_OS)
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#else
+#error "configure failed to detect availability of sys/acl.h"
+#endif
+
+#if !defined(HAVE_LLISTXATTR) || !defined(HAVE_LGETXATTR) || !defined(HAVE_LSETXATTR)
+#error "Missing full support for the XATTR functions."
+#endif
+
+#ifdef HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#else
+#error "Missing sys/xattr.h header file"
+#endif
+
+/*
+ *
+ *
+ */
+class XACL_Linux : public XACL {
+private:
+ bRC_XACL os_backup_acl (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length);
+ bRC_XACL os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length);
+ bRC_XACL os_get_acl(JCR *jcr, XACL_type xacltype);
+ bRC_XACL os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length);
+ bRC_XACL os_get_xattr_names (JCR *jcr, POOLMEM **list, uint32_t *length);
+ bRC_XACL os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen);
+ bRC_XACL os_set_xattr (JCR *jcr, FF_PKT *ff_pkt, char *list, uint32_t length);
+ bRC_XACL os_set_xattr (JCR *jcr, XACL_xattr *xattr);
+ acl_type_t get_acltype(XACL_type xacltype);
+ int acl_nrentries(acl_t acl);
+ bool acl_issimple(acl_t acl);
+public:
+ XACL_Linux ();
+};
+
+#endif /* HAVE_LINUX_OS */
+
+#endif /* __XACL_LINUX_H_ */
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+/**
+ * Major refactoring of ACL and XATTR code written by:
+ *
+ * Radosław Korzeniewski, MMXVI
+ * radoslaw@korzeniewski.net, radekk@inteos.pl
+ * Inteos Sp. z o.o. http://www.inteos.pl/
+ *
+ */
+
+#include "bacula.h"
+#include "filed.h"
+#include "xacl_osx.h"
+
+#if defined(HAVE_DARWIN_OS)
+/*
+ * Define the supported ACL streams for this OS
+ */
+static const int os_acl_streams[] = {
+ STREAM_XACL_DARWIN_ACCESS,
+ 0
+};
+
+static const int os_default_acl_streams[] = {
+ 0
+};
+
+/*
+ * Define the supported XATTR streams for this OS
+ */
+static const int os_xattr_streams[] = {
+ STREAM_XACL_DARWIN_XATTR,
+ 0
+};
+
+static const char *os_xattr_acl_skiplist[] = {
+ "com.apple.system.Security",
+ NULL
+};
+
+static const char *os_xattr_skiplist[] = {
+ "com.apple.system.extendedsecurity",
+ "com.apple.ResourceFork",
+ NULL
+};
+
+/*
+ * OS Specyfic constructor
+ */
+XACL_OSX::XACL_OSX(){
+
+ set_acl_streams(os_acl_streams, os_default_acl_streams);
+ set_xattr_streams(os_xattr_streams);
+ set_xattr_skiplists(os_xattr_skiplist, os_xattr_acl_skiplist);
+};
+
+/*
+ * Translates Bacula internal acl representation into
+ * acl type
+ *
+ * in:
+ * xacltype - internal Bacula acl type (XACL_type)
+ * out:
+ * acl_type_t - os dependent acl type
+ * when failed - ACL_TYPE_NONE is returned
+ */
+acl_type_t XACL_OSX::get_acltype(XACL_type xacltype){
+
+ acl_type_t acltype;
+
+ switch (xacltype){
+ case XACL_TYPE_ACCESS:
+ acltype = ACL_TYPE_ACCESS;
+ break;
+ #ifdef HAVE_ACL_TYPE_EXTENDED
+ case XACL_TYPE_EXTENDED:
+ acltype = ACL_TYPE_EXTENDED;
+ break;
+ #endif
+ default:
+ /*
+ * sanity check for acl's not supported by OS
+ */
+ acltype = (acl_type_t)ACL_TYPE_NONE;
+ break;
+ }
+ return acltype;
+};
+
+/*
+ * Counts a number of acl entries
+ *
+ * in:
+ * acl - acl object
+ * out:
+ * int - number of entries in acl object
+ * when no acl entry available or any error then return zero '0'
+ */
+int XACL_OSX::acl_nrentries(acl_t acl){
+
+ int nr = 0;
+ acl_entry_t entry;
+ int rc;
+
+ rc = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
+ while (rc == 0){
+ nr++;
+ rc = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
+ }
+
+ return nr;
+};
+
+/*
+ * Perform OS specyfic ACL backup
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_OSX::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
+
+ /* check input data */
+ if (jcr == NULL || ff_pkt == NULL){
+ return bRC_XACL_inval;
+ }
+
+#if defined(HAVE_ACL_TYPE_EXTENDED)
+ /*
+ * Use XACL_TYPE_EXTENDED only when available
+ */
+ Dmsg0(400, "MacOSX Extended ACL computed\n");
+ if (os_get_acl(jcr, XACL_TYPE_EXTENDED) == bRC_XACL_fatal){
+ return bRC_XACL_fatal;
+ }
+#else
+ Dmsg0(400, "MacOSX standard ACL computed\n");
+ if (os_get_acl(jcr, XACL_TYPE_ACCESS) == bRC_XACL_fatal){
+ return bRC_XACL_fatal;
+ }
+#endif
+
+ return send_acl_stream(jcr, STREAM_XACL_DARWIN_ACCESS);
+};
+
+/*
+ * Perform OS specyfic ACL restore
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_OSX::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length){
+
+#if defined(HAVE_ACL_TYPE_EXTENDED)
+ return os_set_acl(jcr, XACL_TYPE_EXTENDED, content, length);
+#else
+ return os_set_acl(jcr, XACL_TYPE_ACCESS, content, length);
+#endif
+};
+
+/*
+ * Perform OS specyfic extended attribute backup
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_OSX::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
+ return generic_backup_xattr(jcr, ff_pkt);
+};
+
+/*
+ * Perform OS specyfic XATTR restore. Runtime is called only when stream is supported by OS.
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_OSX::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length){
+ return generic_restore_xattr(jcr, stream);
+};
+
+/*
+ * Low level OS specyfic runtime to get ACL data from file. The ACL data is set in internal content buffer
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_OSX::os_get_acl(JCR *jcr, XACL_type xacltype){
+
+ acl_t acl;
+ acl_type_t acltype;
+ char *acltext;
+ bRC_XACL rc = bRC_XACL_ok;
+
+ /* check input data */
+ if (jcr == NULL){
+ return bRC_XACL_inval;
+ }
+
+ acltype = get_acltype(xacltype);
+ acl = acl_get_file(jcr->last_fname, acltype);
+
+ if (acl){
+ Dmsg1(400, "OS_ACL read from file: %s\n",jcr->last_fname);
+ if (acl_nrentries(acl) == 0){
+ goto bail_out;
+ }
+
+ if ((acltext = acl_to_text(acl, NULL)) != NULL){
+ set_content(acltext);
+ acl_free(acl);
+ acl_free(acltext);
+ return bRC_XACL_ok;
+ }
+
+ berrno be;
+
+ Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "acl_to_text error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+
+ rc = bRC_XACL_error;
+ } else {
+ berrno be;
+
+ switch (errno){
+ case EOPNOTSUPP:
+ /* fs does not support acl, skip it */
+ Dmsg0(400, "Wow, ACL is not supported on this filesystem\n");
+ clear_flag(XACL_FLAG_NATIVE);
+ break;
+ case ENOENT:
+ break;
+ default:
+ /* Some real error */
+ Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "acl_get_file error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ rc = bRC_XACL_error;
+ break;
+ }
+ }
+
+bail_out:
+ if (acl){
+ acl_free(acl);
+ }
+ /*
+ * it is a bit of hardcore to clear a poolmemory with a NULL pointer,
+ * but it is working, hehe :)
+ * you may ask why it is working? it is simple, a pm_strcpy function is handling
+ * a null pointer with a substitiution of empty string.
+ */
+ set_content(NULL);
+ return rc;
+};
+
+/*
+ * Low level OS specyfic runtime to set ACL data on file
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_OSX::os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length){
+
+ acl_t acl;
+ acl_type_t acltype;
+
+ /* check input data */
+ if (jcr == NULL || content == NULL){
+ return bRC_XACL_inval;
+ }
+
+ acl = acl_from_text(content);
+ if (acl == NULL){
+ berrno be;
+
+ Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+
+ acltype = get_acltype(xacltype);
+
+ /*
+ * Restore the ACLs, but don't complain about links which really should
+ * not have attributes, and the file it is linked to may not yet be restored.
+ * This is only true for the old acl streams as in the new implementation we
+ * don't save acls of symlinks (which cannot have acls anyhow)
+ */
+ if (acl_set_file(jcr->last_fname, acltype, acl) != 0 && jcr->last_type != FT_LNK){
+ berrno be;
+ switch (errno){
+ case ENOENT:
+ acl_free(acl);
+ return bRC_XACL_ok;
+ case EOPNOTSUPP:
+ /*
+ * If the filesystem reports it doesn't support ACLs we clear the
+ * XACL_FLAG_NATIVE flag so we skip ACL restores on all other files
+ * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
+ * when we change from one filesystem to an other.
+ */
+ clear_flag(XACL_FLAG_NATIVE);
+ Mmsg1(jcr->errmsg, _("acl_set_file error on file \"%s\": filesystem doesn't support ACLs\n"), jcr->last_fname);
+ Dmsg2(100, "acl_set_file error acl=%s file=%s filesystem doesn't support ACLs\n", content, jcr->last_fname);
+ acl_free(acl);
+ return bRC_XACL_error;
+ default:
+ Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
+ acl_free(acl);
+ return bRC_XACL_error;
+ }
+ }
+ acl_free(acl);
+ return bRC_XACL_ok;
+};
+
+/*
+ * Return a list of xattr names in newly allocated pool memory and a length of the allocated buffer.
+ * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
+ * when not needed.
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_OSX::os_get_xattr_names (JCR *jcr, POOLMEM ** pxlist, uint32_t * xlen){
+
+ int len;
+ POOLMEM * list;
+
+ /* check input data */
+ if (jcr == NULL || xlen == NULL || pxlist == NULL){
+ return bRC_XACL_inval;
+ }
+ /* get the length of the extended attributes */
+ len = listxattr(jcr->last_fname, NULL, 0, XATTR_NOFOLLOW);
+ switch (len){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it */
+ return bRC_XACL_skip;
+ case ENOTSUP:
+ /* no xattr supported on filesystem, clear a flag and skip it */
+ clear_flag(XACL_FLAG_NATIVE);
+ set_content(NULL);
+ return bRC_XACL_skip;
+ default:
+ Mmsg2(jcr->errmsg, _("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 bRC_XACL_error;
+ }
+ break;
+ }
+ case 0:
+ /* xattr available but empty, skip it */
+ return bRC_XACL_skip;
+ default:
+ break;
+ }
+
+ /*
+ * allocate memory for the extented attribute list
+ * default size is a 4k for PM_BSOCK, which should be sufficient on almost all
+ * Linux system where xattrs a limited in size to single filesystem block ~4kB
+ * so we need to check required size
+ */
+ list = get_pool_memory(PM_BSOCK);
+ list = check_pool_memory_size(list, len + 1);
+ memset(list, 0, len + 1);
+
+ /* get the list of extended attributes names for a file */
+ len = listxattr(jcr->last_fname, list, len, XATTR_NOFOLLOW);
+ switch (len){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it, first release allocated memory */
+ free_pool_memory(list);
+ return bRC_XACL_skip;
+ default:
+ Mmsg2(jcr->errmsg, _("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_pool_memory(list);
+ return bRC_XACL_error;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ /* ensure a list is nul terminated */
+ list[len] = '\0';
+ /* setup return data */
+ *pxlist = list;
+ *xlen = len;
+ return bRC_XACL_ok;
+};
+
+/*
+ * Return a value of the requested attribute name and a length of the allocated buffer.
+ * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
+ * when not needed.
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_OSX::os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen){
+
+ int len;
+ POOLMEM * value;
+
+ /* check input data */
+ if (jcr == NULL || name == NULL || plen == NULL || pvalue == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* get the length of the value for extended attribute */
+ len = getxattr(jcr->last_fname, name, NULL, 0, 0, XATTR_NOFOLLOW);
+ switch (len){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it */
+ return bRC_XACL_skip;
+ default:
+ /* XXX: what about ENOATTR error value? */
+ Mmsg2(jcr->errmsg, _("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());
+ return bRC_XACL_error;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (len > 0){
+ /*
+ * allocate memory for the extented attribute value
+ * default size is a 256B for PM_MESSAGE, so we need to check required size
+ */
+ value = get_pool_memory(PM_MESSAGE);
+ value = check_pool_memory_size(value, len + 1);
+ memset(value, 0, len + 1);
+ /* value is not empty, get a data */
+ len = getxattr(jcr->last_fname, name, value, len, 0, XATTR_NOFOLLOW);
+ switch (len){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it, first release allocated memory */
+ free_pool_memory(value);
+ return bRC_XACL_skip;
+ default:
+ Mmsg2(jcr->errmsg, _("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());
+ free_pool_memory(value);
+ return bRC_XACL_error;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ /* ensure a value is nul terminated */
+ value[len] = '\0';
+ } else {
+ /* empty value */
+ value = NULL;
+ len = 0;
+ }
+ /* setup return data */
+ *pvalue = value;
+ *plen = len;
+ return bRC_XACL_ok;
+};
+
+/*
+ * Low level OS specyfic runtime to set extended attribute on file
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_OSX::os_set_xattr (JCR *jcr, XACL_xattr *xattr){
+
+ /* check input data */
+ if (jcr == NULL || xattr == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* set extattr on file */
+ if (setxattr(jcr->last_fname, xattr->name, xattr->value, xattr->value_len, 0, XATTR_NOFOLLOW) != 0){
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ break;
+ case ENOTSUP:
+ /*
+ * If the filesystem reports it doesn't support XATTR we clear the
+ * XACL_FLAG_NATIVE flag so we skip XATTR restores on all other files
+ * on the same filesystem. The XACL_FLAG_NATIVE flag gets set again
+ * when we change from one filesystem to an other.
+ */
+ clear_flag(XACL_FLAG_NATIVE);
+ Mmsg1(jcr->errmsg, _("setxattr error on file \"%s\": filesystem doesn't support XATTR\n"), jcr->last_fname);
+ Dmsg3(100, "setxattr error name=%s value=%s file=%s filesystem doesn't support XATTR\n", xattr->name, xattr->value, jcr->last_fname);
+ break;
+ default:
+ Mmsg2(jcr->errmsg, _("setxattr error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "setxattr error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ }
+ return bRC_XACL_ok;
+};
+
+#endif /* HAVE_DARWIN_OS */
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+/**
+ * Major refactoring of ACL and XATTR code written by:
+ *
+ * Radosław Korzeniewski, MMXVI
+ * radoslaw@korzeniewski.net, radekk@inteos.pl
+ * Inteos Sp. z o.o. http://www.inteos.pl/
+ *
+ */
+
+#ifndef __XACL_OSX_H_
+#define __XACL_OSX_H_
+
+#if defined(HAVE_DARWIN_OS)
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#else
+#error "configure failed to detect availability of sys/acl.h"
+#endif
+
+#if !defined(HAVE_LISTXATTR) || !defined(HAVE_GETXATTR) || !defined(HAVE_SETXATTR)
+#error "Missing full support for the XATTR functions."
+#endif
+
+#ifdef HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#else
+#error "Missing sys/xattr.h header file"
+#endif
+
+/*
+ *
+ *
+ */
+class XACL_OSX : public XACL {
+private:
+ bRC_XACL os_backup_acl (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length);
+ bRC_XACL os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length);
+ bRC_XACL os_get_acl(JCR *jcr, XACL_type xacltype);
+ bRC_XACL os_set_acl(JCR *jcr, XACL_type xacltype, char *content, uint32_t length);
+ bRC_XACL os_get_xattr_names (JCR *jcr, POOLMEM **list, uint32_t *length);
+ bRC_XACL os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen);
+ bRC_XACL os_set_xattr (JCR *jcr, XACL_xattr *xattr);
+ /* requires acl.h available */
+ acl_type_t get_acltype(XACL_type xacltype);
+ int acl_nrentries(acl_t acl);
+public:
+ XACL_OSX ();
+};
+
+#endif /* HAVE_DARWIN_OS */
+
+#endif /* __XACL_OSX_H_ */
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+/**
+ * Major refactoring of ACL and XATTR code written by:
+ *
+ * Radosław Korzeniewski, MMXVI
+ * radoslaw@korzeniewski.net, radekk@inteos.pl
+ * Inteos Sp. z o.o. http://www.inteos.pl/
+ *
+ */
+
+#include "bacula.h"
+#include "filed.h"
+#include "xacl_solaris.h"
+
+#if defined(HAVE_SUN_OS)
+/*
+ * Define the supported ACL streams for this OS
+ */
+static const int os_acl_streams[] = {
+ STREAM_XACL_SOLARIS_POSIX,
+ STREAM_XACL_SOLARIS_NFS4,
+ 0
+};
+
+static const int os_default_acl_streams[] = {
+ 0
+};
+
+/*
+ * Define the supported XATTR streams for this OS
+ */
+static const int os_xattr_streams[] = {
+ STREAM_XACL_SOLARIS_XATTR,
+#if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
+ STREAM_XACL_SOLARIS_SYS_XATTR,
+#endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
+ 0
+};
+
+
+static const char *os_xattr_acl_skiplist[] = {
+ NULL
+};
+
+static const char *os_xattr_skiplist[] = {
+ "..",
+#if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
+ VIEW_READONLY,
+#endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
+ NULL
+};
+
+/*
+ * OS Specyfic constructor
+ */
+XACL_Solaris::XACL_Solaris(){
+
+ set_acl_streams(os_acl_streams, os_default_acl_streams);
+ set_xattr_streams(os_xattr_streams);
+ set_xattr_skiplists(os_xattr_skiplist, os_xattr_acl_skiplist);
+ cache = NULL;
+};
+
+/*
+ * OS Specyfic destructor
+ */
+XACL_Solaris::~XACL_Solaris(){
+
+ delete_xattr_cache();
+};
+
+/*
+ * Checks if ACL's are available for a specified file
+ *
+ * in:
+ * jcr - Job Control Record
+ * name - specifies the system variable to be queried
+ * out:
+ * bRC_XACL_ok - check successful, lets setup xacltype variable
+ * bRC_XACL_error - in case of error
+ * bRC_XACL_skip - you should skip all other routine
+ */
+bRC_XACL XACL_Solaris::check_xacltype (JCR *jcr, int name){
+
+ int rc = 0;
+
+ rc = pathconf(jcr->last_fname, name);
+ switch (rc){
+ case -1: {
+ /* some error check why */
+ berrno be;
+ if (errno == ENOENT){
+ /* file does not exist skip it */
+ return bRC_XACL_skip;
+ } else {
+ Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "pathconf error file=%s ERR=%s\n", jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ }
+ case 0:
+ /* No support for ACLs */
+ clear_flag(XACL_FLAG_NATIVE);
+ set_content(NULL);
+ return bRC_XACL_skip;
+ default:
+ break;
+ }
+ return bRC_XACL_ok;
+};
+
+/*
+ * Perform OS specyfic ACL backup
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Solaris::os_backup_acl (JCR *jcr, FF_PKT *ff_pkt){
+
+ bRC_XACL rc;
+ int stream;
+
+ /*
+ * See if filesystem supports acls.
+ */
+ rc = check_xacltype(jcr, _PC_ACL_ENABLED);
+ switch (rc){
+ case bRC_XACL_ok:
+ break;
+ case bRC_XACL_skip:
+ return bRC_XACL_ok;
+ default:
+ /* errors */
+ return rc;
+ }
+
+ rc = os_get_acl(jcr, &stream);
+ switch (rc){
+ case bRC_XACL_ok:
+ if (get_content_len() > 0){
+ if (send_acl_stream(jcr, stream) == bRC_XACL_fatal){
+ return bRC_XACL_fatal;
+ }
+ }
+ break;
+ default:
+ return rc;
+ }
+
+ return bRC_XACL_ok;
+};
+
+/*
+ * Perform OS specyfic ACL restore
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Solaris::os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length){
+
+ int aclrc = 0;
+
+ switch (stream){
+ case STREAM_UNIX_ACCESS_ACL:
+ case STREAM_XACL_SOLARIS_POSIX:
+ case STREAM_XACL_SOLARIS_NFS4:
+ aclrc = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
+ break;
+ default:
+ return bRC_XACL_error;
+ }
+
+ switch (aclrc){
+ case -1: {
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ return bRC_XACL_ok;
+ default:
+ Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ }
+ case 0:
+ clear_flag(XACL_FLAG_NATIVE);
+ Mmsg(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"), jcr->last_fname);
+ return bRC_XACL_error;
+ default:
+ break;
+ }
+
+ switch (stream){
+ case STREAM_XACL_SOLARIS_POSIX:
+ if ((aclrc & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0){
+ Mmsg(jcr->errmsg, _("Trying to restore POSIX acl on file \"%s\" on filesystem without aclent acl support\n"), jcr->last_fname);
+ return bRC_XACL_error;
+ }
+ break;
+ case STREAM_XACL_SOLARIS_NFS4:
+ if ((aclrc & _ACL_ACE_ENABLED) == 0){
+ Mmsg(jcr->errmsg, _("Trying to restore NFSv4 acl on file \"%s\" on filesystem without ace acl support\n"), jcr->last_fname);
+ return bRC_XACL_error;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return os_set_acl(jcr, stream, content, length);
+};
+
+/*
+ * Perform OS specyfic extended attribute backup
+ *
+ * in/out - check API at xacl.h
+ *
+ * The Solaris implementation of XATTR is very, very different then all other "generic" unix implementations,
+ * so the original author of the Bacula XATTR support for Solaris OS decided to totally change the Xattr Stream
+ * content, and we need to follow this design to support previous behavior. The stream consist of a number of
+ * "files" with STREAM_XACL_SOLARIS_XATTR or STREAM_XACL_SOLARIS_SYS_XATTR stream' id. Every singe stream represents
+ * a single attibute. The content is a NULL-terminated array with a following data:
+ * <xattr name>\0<encoded stat>\0<acl rendered text>\0<xattr data>
+ * when an attribute file has a hardlinked other attributes then a content stream changes a bit into:
+ * <xattr name>\0<encoded stat>\0<target xattr name>\0
+ * where:
+ * <xattr name> is an attribute name - a file name in Solaris
+ * <encoded stat> is a standard file stat struct encoded by Bacula (the same encoding goes with a regular file)
+ * <acl rendered text> is a Solaris dependent acltotext data
+ * <xattr data> is the attribute file raw content
+ * <target xattr name> is a name of the first hardlinked attribute file which a current attribute has to linked to
+ *
+ * The raw content of the attribute is copied into memory before send to the SD and for a very large attribute
+ * data can allocate a large amount of additional memory. In most cases it should not be a problem because most
+ * xattrs should has a few /hundred/ bytes in size. This is the same behavior as in previous implementation.
+ */
+bRC_XACL XACL_Solaris::os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt){
+
+ bRC_XACL rc;
+ POOLMEM *xlist = NULL;
+ uint32_t xlen;
+ char *name;
+ char *lnkname;
+ uint32_t name_len;
+ POOLMEM *value = NULL;
+ uint32_t value_len;
+ char * xacltext;
+ uint32_t xacltext_len;
+ POOLMEM *data = NULL;
+ bool skip;
+ struct stat st;
+ char attribs[MAXSTRING];
+ int stream;
+ int attrfd;
+ int len;
+
+ /* sanity check of input variables */
+ if (jcr == NULL || ff_pkt == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* check if extended/extensible attributes are present */
+ if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0){
+ /* xlist is allocated as POOLMEM by os_get_xattr_names */
+ rc = os_get_xattr_names(jcr, &xlist, &xlen);
+ switch (rc){
+ case bRC_XACL_ok:
+ /* it's ok, so go further */
+ break;
+ case bRC_XACL_skip:
+ case bRC_XACL_cont:
+ /* no xattr available, so skip rest of it */
+ return bRC_XACL_ok;
+ default:
+ return rc;
+ }
+
+ data = get_pool_memory(PM_BSOCK);
+ /* follow the list of xattr names and get the values */
+ for (name = xlist; (name - xlist) + 1 < xlen; name = strchr(name, '\0') + 1){
+ name_len = strlen(name);
+ /* skip read-only or other unused attribute names */
+ skip = check_xattr_skiplists(jcr, ff_pkt, name);
+ if (skip || name_len == 0){
+ Dmsg1(100, "Skipping xattr named \"%s\"\n", name);
+ continue;
+ }
+ /* set a correct stream */
+ stream = STREAM_XACL_SOLARIS_XATTR;
+
+#if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
+ /* check for system attributes name */
+ if (bstrcmp(name, VIEW_READWRITE)){
+ stream = STREAM_XACL_SOLARIS_SYS_XATTR;
+ }
+#endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
+
+ /* open an attribute descriptor, it will be used for backup */
+ attrfd = attropen(jcr->last_fname, name, O_RDONLY);
+
+ /* get the stat of the attribute */
+ if (fstat(attrfd, &st) < 0){
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ rc = bRC_XACL_ok;
+ goto bailout;
+ default:
+ Mmsg3(jcr->errmsg, _("Unable to get status on xattr \"%s\" on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n", name, jcr->last_fname, be.bstrerror());
+ rc = bRC_XACL_error;
+ goto bailout;
+ }
+ }
+
+ /* we have a struct stat of the attribute so encode it to the buffer */
+ encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
+
+ /* get xattr acl data, but only when it is not trivial acls */
+ rc = os_get_xattr_acl(jcr, attrfd, &xacltext);
+ if (rc != bRC_XACL_ok){
+ goto bailout;
+ }
+ xacltext_len = strlen(xacltext);
+
+ /*
+ * Solaris support only S_IFREG and S_IFDIR as an attribute file type, no other types are supported
+ * the previous Solaris xattr implementation in Bacula had an unverified and untested code for other
+ * types of attribute files which was a nonsense and unnecessarily complicate the code. We decided
+ * to remove unsupported code. To check if the current Solaris version support for xattr was extended
+ * simply verify a man fsattr(5) for it.
+ */
+ switch (st.st_mode & S_IFMT){
+ case S_IFREG:
+ /* check for hardlinked attributes which solaris support */
+ if (st.st_nlink > 1){
+ /* search for already saved file of the same inode number */
+ lnkname = find_xattr_cache(jcr, st.st_ino, name);
+ if (lnkname != NULL){
+ /* found a previous saved file, link to it and render xattr data for hardlinked attribute */
+ len = bsnprintf(data, sizeof_pool_memory(data), "%s%c%s%c%s%c", name, 0, attribs, 0, lnkname, 0);
+ set_content(data, len);
+ /* content is ready */
+ break;
+ }
+ }
+ /* value is allocated as POOLMEM by os_get_xattr_value */
+ rc = os_get_xattr_value(jcr, name, &value, &value_len);
+ switch (rc){
+ case bRC_XACL_ok:
+ /* it's ok, so go further */
+ break;
+ case bRC_XACL_skip:
+ /* no xattr available, so skip rest of it */
+ rc = bRC_XACL_ok;
+ goto bailout;
+ default:
+ /* error / fatal */
+ goto bailout;
+ }
+ /* save xattr info */
+ len = bsnprintf(data, sizeof_pool_memory(data), "%s%c%s%c%s%c", name, 0, attribs, 0, (xacltext) ? xacltext : "", 0);
+ /* append value data to the end of the xattr info */
+ check_pool_memory_size(data, len + value_len);
+ memcpy(data + len, value, value_len);
+ set_content(data,len + value_len);
+ free_pool_memory(value);
+ value = NULL;
+ break;
+ case S_IFDIR:
+ /* save xattr info */
+ len = bsnprintf(data, sizeof_pool_memory(data), "%s%c%s%c%s%c", name, 0, attribs, 0, (xacltext) ? xacltext : "", 0);
+ set_content(data);
+ default:
+ Mmsg3(jcr->errmsg, _("Unsupported extended attribute type: %i for \"%s\" on file \"%s\"\n"), st.st_mode & S_IFMT, name, jcr->last_fname);
+ Dmsg3(100, "Unsupported extended attribute type: %i for \"%s\" on file \"%s\"\n", st.st_mode & S_IFMT, name, jcr->last_fname);
+ rc = bRC_XACL_error;
+ goto bailout;
+ }
+ /* send stream to the sd */
+ rc = send_xattr_stream(jcr, stream);
+ if (rc != bRC_XACL_ok){
+ Mmsg2(jcr->errmsg, _("Failed to send extended attribute \"%s\" on file \"%s\"\n"), name, jcr->last_fname);
+ Dmsg2(100, "Failed to send extended attribute \"%s\" on file \"%s\"\n", name, jcr->last_fname);
+ goto bailout;
+ }
+ }
+
+bailout:
+ /* free allocated data: xlist, value (if not freed), data, etc. */
+ free_pool_memory(data);
+ if (value != NULL){
+ free_pool_memory(value);
+ }
+ if (xlist != NULL){
+ free_pool_memory(xlist);
+ }
+ /* this is a cache for a particular file, so no needed after backup of this file */
+ delete_xattr_cache();
+
+ return rc;
+ }
+ return bRC_XACL_ok;
+};
+
+/*
+ * XACL_Solaris cache is a simple linked list cache of inode number and names used to handle
+ * xattr hard linked data. The function is searching for cached entry. When not found it append
+ * entry to the cache.
+ * in:
+ * jcr - Job Control Record (well, it is not used here)
+ * ino - inode number to compare/search for
+ * name - the name of the current attribute
+ * out:
+ * NULL - when entry not found in cache and new entry was added
+ * <str> - a name of the linked entry
+ */
+inline char * XACL_Solaris::find_xattr_cache(JCR *jcr, ino_t ino, char * name){
+
+ XACL_Solaris_Cache *entry;
+
+ if (cache != NULL){
+ foreach_alist(entry, cache){
+ if (entry && entry->inode == ino){
+ /* found in cache, return name */
+ return entry->name;
+ }
+ }
+ } else {
+ cache = New (alist(10, not_owned_by_alist));
+ }
+ /* not found, so add this one to the cache */
+ entry = (XACL_Solaris_Cache*) malloc (sizeof(XACL_Solaris_Cache));
+ entry->inode = ino;
+ entry->name = name;
+ cache->append(entry);
+ return NULL;
+}
+
+/*
+ * The function deletes a cache
+ * in/out - void
+ */
+inline void XACL_Solaris::delete_xattr_cache(){
+
+ XACL_Solaris_Cache *entry;
+
+ if (cache != NULL){
+ foreach_alist(entry, cache){
+ free(entry);
+ }
+ delete cache;
+ cache = NULL;
+ }
+}
+
+/*
+ * Perform OS specyfic XATTR restore. Runtime is called only when stream is supported by OS.
+ *
+ * The way Solaris xattr support is designed in Bacula we will have a single attribute restore
+ * with every call to this function. So multiple attributes are restored with multiple calls.
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Solaris::os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length){
+
+ bRC_XACL rc = bRC_XACL_error;
+ bool extended = false;
+
+ /* check input data */
+ if (jcr == NULL || content == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* First make sure we can restore xattr on the filesystem */
+ switch (stream){
+#if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
+ case STREAM_XACL_SOLARIS_SYS_XATTR:
+ if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0){
+ Mmsg(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"), jcr->last_fname);
+ Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n", jcr->last_fname);
+ goto bail_out;
+ }
+ extended = true;
+ break;
+#endif
+ case STREAM_XACL_SOLARIS_XATTR:
+ if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0){
+ Mmsg(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"), jcr->last_fname);
+ Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n", jcr->last_fname);
+ goto bail_out;
+ }
+ break;
+ default:
+ goto bail_out;
+ }
+
+ rc = os_set_xattr(jcr, extended, content, length);
+
+bail_out:
+ return rc;
+};
+
+/*
+ * Low level OS specyfic runtime to get ACL data from file. The ACL data is set in internal content buffer
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Solaris::os_get_acl(JCR *jcr, int *stream){
+
+ int flags;
+ acl_t *aclp;
+ char *acl_text;
+ bRC_XACL rc = bRC_XACL_fatal;
+
+ if (!stream){
+ return bRC_XACL_fatal;
+ }
+
+ if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0){
+ /* we've got some error */
+ berrno be;
+ switch (errno){
+ case ENOENT:
+ /* file does not exist */
+ return bRC_XACL_ok;
+ default:
+ Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"), jcr->last_fname, acl_strerror(errno));
+ Dmsg2(100, "acl_get error file=%s ERR=%s\n", jcr->last_fname, acl_strerror(errno));
+ return bRC_XACL_error;
+ }
+ }
+
+ if (!aclp){
+ /*
+ * The ACLs simply reflect the (already known) standard permissions
+ * So we don't send an ACL stream to the SD.
+ */
+ set_content(NULL);
+ return bRC_XACL_ok;
+ }
+
+#if defined(ACL_SID_FMT)
+ /* new format flag added in newer Solaris versions */
+ flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
+#else
+ flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
+#endif /* ACL_SID_FMT */
+
+ if ((acl_text = acl_totext(aclp, flags)) != NULL){
+ set_content(acl_text);
+ actuallyfree(acl_text);
+
+ switch (acl_type(aclp)){
+ case ACLENT_T:
+ *stream = STREAM_XACL_SOLARIS_POSIX;
+ break;
+ case ACE_T:
+ *stream = STREAM_XACL_SOLARIS_NFS4;
+ break;
+ default:
+ rc = bRC_XACL_error;
+ break;
+ }
+
+ acl_free(aclp);
+ }
+ return rc;
+};
+
+/*
+ * Low level OS specyfic runtime to get ACL on XATTR. The ACL data is set in supplied buffer
+ *
+ * in:
+ * jcr - Job Control Record
+ * fd - an opened file descriptor of the saved attribute
+ * buffer - a pointer to the memory buffer where we will render an acl text
+ * out:
+ * bRC_XACL_ok - backup acl for extended attribute finish without problems
+ * bRC_XACL_error - backup acl unsuccessful
+ * bRC_XACL_inval - input variables are invalid (null)
+ *
+ */
+bRC_XACL XACL_Solaris::os_get_xattr_acl(JCR *jcr, int fd, char **buffer){
+
+// a function is valid only when Bacula have a support for ACL
+#ifdef HAVE_ACL
+ bRC_XACL rc = bRC_XACL_error;
+
+ /* sanity check of input variables */
+ if (jcr == NULL || buffer == NULL || *buffer == NULL || fd < 0){
+ return bRC_XACL_inval;
+ }
+
+#ifdef HAVE_EXTENDED_ACL
+
+ int flags;
+ acl_t *aclp = NULL;
+
+ /* check if an attribute has acl on it which we can save */
+ if (fpathconf(fd, _PC_ACL_ENABLED) > 0){
+ /* check for non trivial acl on the file */
+ if (facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0){
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ rc = bRC_XACL_ok;
+ goto bail_out;
+ default:
+ Mmsg2(jcr->errmsg, _("Unable to get xattr acl on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "facl_get/acl_get of xattr on \"%s\" failed: ERR=%s\n", jcr->last_fname, be.bstrerror());
+ goto bail_out;
+ }
+ }
+
+ if (aclp != NULL){
+#if defined(ACL_SID_FMT)
+ /* New format flag added in newer Solaris versions. */
+ flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
+#else
+ flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
+#endif /* ACL_SID_FMT */
+
+ *buffer = acl_totext(aclp, flags);
+ acl_free(aclp);
+ } else {
+ *buffer = NULL;
+ }
+ } else {
+ *buffer = NULL;
+ }
+ rc = bRC_XACL_ok;
+bail_out:
+
+#else /* !HAVE_EXTENDED_ACL */
+
+ int n;
+ aclent_t *acls = NULL;
+
+ /* See if this attribute has an ACL */
+ if (fd != -1){
+ n = facl(fd, GETACLCNT, 0, NULL);
+ } else {
+ n = acl(attrname, GETACLCNT, 0, NULL);
+ }
+
+ if (n >= MIN_ACL_ENTRIES){
+ acls = (aclent_t *)malloc(n * sizeof(aclent_t));
+ if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
+ acl(attrname, GETACL, n, acls) != n){
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ free(acls);
+ retval = bRC_XACL_ok;
+ goto bail_out;
+ default:
+ Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"), attrname, jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n", attrname, jcr->last_fname, be.bstrerror());
+ free(acls);
+ goto bail_out;
+ }
+ }
+
+ /* See if there is a non trivial acl on the file. */
+ if (!acl_is_trivial(n, acls)){
+ if ((*acl_text = acltotext(acls, n)) == NULL){
+ berrno be;
+
+ Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"), attrname, jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n", attrname, jcr->last_fname, be.bstrerror());
+ free(acls);
+ goto bail_out;
+ }
+ } else {
+ *buffer = NULL;
+ }
+
+ free(acls);
+ } else {
+ *buffer = NULL;
+ }
+ rc = bRC_XACL_ok;
+#endif /* HAVE_EXTENDED_ACL */
+ return rc;
+#else /* HAVE_ACL */
+ return bRC_XACL_ok;
+#endif /* HAVE_ACL */
+}
+
+/*
+ * Low level OS specyfic runtime to set ACL on XATTR. The ACL data is set from supplied text
+ *
+ * in:
+ * jcr - Job Control Record
+ * fd - an opened file descriptor of the restored attribute
+ * buffer - a pointer to the memory buffer where we will render an acl text
+ * out:
+ * bRC_XACL_ok - backup acl for extended attribute finish without problems
+ * bRC_XACL_inval - input variables are invalid (null)
+ *
+ */
+bRC_XACL XACL_Solaris::os_set_xattr_acl(JCR *jcr, int fd, char *name, char *acltext){
+
+// a function is valid only when Bacula have a support for ACL
+#ifdef HAVE_ACL
+
+ bRC_XACL rc = bRC_XACL_error;
+
+ /* sanity check of input variables */
+ if (jcr == NULL || name == NULL || acltext == NULL || fd < 0){
+ return bRC_XACL_inval;
+ }
+
+#ifdef HAVE_EXTENDED_ACL
+
+ int error;
+ acl_t *aclp = NULL;
+
+ if ((error = acl_fromtext(acltext, &aclp)) != 0){
+ Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"), jcr->last_fname);
+ return bRC_XACL_error;
+ }
+
+ if (fd != -1 && facl_set(fd, aclp) != 0){
+ berrno be;
+
+ Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
+ rc = bRC_XACL_error;
+ }
+
+bail_out:
+ if (aclp){
+ acl_free(aclp);
+ }
+
+#else /* !HAVE_EXTENDED_ACL */
+
+ int n;
+ aclent_t *acls = NULL;
+
+ acls = aclfromtext(acltext, &n);
+ if (acls){
+ if (fd != -1 && facl(fd, SETACL, n, acls) != 0){
+ berrno be;
+
+ Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
+ rc = bRC_XACL_error;
+ }
+ free(acls);
+ }
+
+#endif /* HAVE_EXTENDED_ACL */
+
+ return rc;
+#else /* HAVE_ACL */
+ return bRC_XACL_ok;
+#endif /* HAVE_ACL */
+};
+
+/*
+ * Low level OS specyfic runtime to set ACL data on file
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Solaris::os_set_acl(JCR *jcr, int stream, char *content, uint32_t length){
+
+ int rc;
+ acl_t *aclp;
+
+ if ((rc = acl_fromtext(content, &aclp)) != 0){
+ Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"), jcr->last_fname, acl_strerror(rc));
+ Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, acl_strerror(rc));
+ return bRC_XACL_error;
+ }
+
+ switch (stream){
+ case STREAM_XACL_SOLARIS_POSIX:
+ if (acl_type(aclp) != ACLENT_T){
+ Mmsg(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"), jcr->last_fname);
+ return bRC_XACL_error;
+ }
+ break;
+ case STREAM_XACL_SOLARIS_NFS4:
+ if (acl_type(aclp) != ACE_T){
+ Mmsg(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"), jcr->last_fname);
+ return bRC_XACL_error;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if ((rc = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK){
+ switch (errno){
+ case ENOENT:
+ acl_free(aclp);
+ return bRC_XACL_ok;
+ default:
+ Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"), jcr->last_fname, acl_strerror(rc));
+ Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n", content, jcr->last_fname, acl_strerror(rc));
+ acl_free(aclp);
+ return bRC_XACL_error;
+ }
+ }
+
+ acl_free(aclp);
+ return bRC_XACL_ok;
+};
+
+/*
+ * Return a list of xattr names in newly allocated pool memory and a length of the allocated buffer.
+ * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
+ * when not needed.
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Solaris::os_get_xattr_names (JCR *jcr, POOLMEM ** pxlist, uint32_t * xlen){
+
+ int xattrdfd;
+ DIR *dirp;
+ struct dirent *dp;
+
+ int len;
+ int slen;
+ POOLMEM * list;
+ char * p;
+
+ /* check input data */
+ if (jcr == NULL || xlen == NULL || pxlist == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* Open the xattr stream on file */
+ if ((xattrdfd = attropen(jcr->last_fname, ".", O_RDONLY)) < 0){
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it */
+ return bRC_XACL_skip;
+ case EINVAL:
+ /* no xattr supported on file skip it */
+ return bRC_XACL_skip;
+ default:
+ Mmsg2(jcr->errmsg, _("Unable to open xattr on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "Unable to open xattr on file \"%s\": ERR=%s\n", jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ }
+
+ /* open an extended file directory to read all xattr names */
+ if ((dirp = fdopendir(xattrdfd)) == (DIR *)NULL){
+ berrno be;
+
+ Mmsg2(jcr->errmsg, _("Unable to list the xattr on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "Unable to fdopendir xattr on file \"%s\" using fd %d: ERR=%s\n", jcr->last_fname, xattrdfd, be.bstrerror());
+ close(xattrdfd);
+ return bRC_XACL_error;
+ }
+
+ /*
+ * allocate memory for the extented attribute list
+ * default size is a 4k for PM_BSOCK, which should be sufficient in most cases
+ */
+ list = p = get_pool_memory(PM_BSOCK);
+ memset(list, 0, sizeof_pool_memory(list));
+ len = 0;
+
+ /* read all directory entries as a xattr names */
+ while ((dp = readdir(dirp)) != NULL){
+
+ /* skip '..' name as it a file we backup */
+ if (bstrcmp(dp->d_name, "..") == 0){
+ continue;
+ }
+
+#if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
+ /* skip a read only attributes which we cant restore later */
+ if (bstrcmp(dp->d_name, VIEW_READONLY)){
+ Dmsg2(400, "Skipping readonly extensible attributes %s on file \"%s\"\n", dp->d_name, jcr->last_fname);
+ continue;
+ }
+#endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
+
+ /* compute a buffer length = string length and nul char */
+ slen = strlen (dp->d_name);
+ len += slen + 1;
+ list = check_pool_memory_size(list, len);
+
+ /* copy the name into a list */
+ bstrncpy(p, dp->d_name, slen);
+ p[slen] = '\0';
+ p += slen + 1;
+ }
+ if (closedir(dirp) < 0){
+ berrno be;
+
+ Mmsg2(jcr->errmsg, _("Unable to close xattr list on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "Unable to close xattr list on file \"%s\": ERR=%s\n", jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+
+ *pxlist = list;
+ *xlen = len;
+
+ return bRC_XACL_ok;
+};
+
+/*
+ * Return a value of the requested attribute name and a length of the allocated buffer.
+ * It allocates a memory with poolmem subroutines every time a function is called, so it must be freed
+ * when not needed.
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Solaris::os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen){
+
+ int xattrfd;
+ int len;
+ POOLMEM * value;
+ struct stat st;
+
+ /* check input data */
+ if (jcr == NULL || name == NULL || plen == NULL || pvalue == NULL){
+ return bRC_XACL_inval;
+ }
+
+ /* Open the xattr on file */
+ if ((xattrfd = attropen(jcr->last_fname, name, O_RDONLY)) < 0){
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it */
+ return bRC_XACL_skip;
+ case EINVAL:
+ /* no xattr supported on file skip it */
+ return bRC_XACL_skip;
+ default:
+ Mmsg2(jcr->errmsg, _("Unable to open xattr on file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "Unable to open xattr on file \"%s\": ERR=%s\n", jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ }
+
+ /* get some info about extended attribute */
+ if (fstat(xattrfd, &st) < 0){
+ berrno be;
+
+ switch (errno){
+ case ENOENT:
+ /* no file available, skip it */
+ return bRC_XACL_skip;
+ default:
+ Mmsg3(jcr->errmsg, _("Unable to stat xattr \"%s\" on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "Unable to stat xattr \"%s\" on file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
+ return bRC_XACL_error;
+ }
+ }
+
+ /* default empty value */
+ value = NULL;
+ len = 0;
+
+ /* only a file has a data/value we should care about */
+ if ((st.st_mode & S_IFMT) != S_IFDIR){
+ /* get size of the attribute data/value */
+ len = lseek(xattrfd, 0, SEEK_END);
+ lseek(xattrfd, 0, SEEK_SET);
+ }
+ if (len > 0){
+ /*
+ * allocate memory for the extented attribute value
+ * default size is a 256B for PM_MESSAGE, so we need to check required size
+ */
+ value = get_pool_memory(PM_MESSAGE);
+ value = check_pool_memory_size(value, len);
+ memset(value, 0, len);
+ /* read teh data */
+ read (xattrfd, value, len);
+ close(xattrfd);
+ }
+
+ /* setup return data */
+ *pvalue = value;
+ *plen = len;
+ return bRC_XACL_ok;
+};
+
+/*
+ * Low level OS specyfic runtime to set extended attribute on file
+ *
+ * in/out - check API at xacl.h
+ */
+bRC_XACL XACL_Solaris::os_set_xattr (JCR *jcr, bool extended, char *content, uint32_t length){
+
+ char *bp = content + 1; /* original code saves attribute name with '/' */
+ char *name;
+ char *attribs;
+ char *acltext;
+ char *lntarget;
+ int attrfd = 0;
+ int attrdirfd = 0;
+ int cnt;
+ int len;
+ int inum;
+ struct stat st;
+ struct timeval times[2];
+ bRC_XACL rc = bRC_XACL_ok;
+
+ /* check input data */
+ if (jcr == NULL || content == NULL){
+ return bRC_XACL_inval;
+ }
+ /*
+ * Parse content stream and extract valuable data.
+ * STD/EXT: <xattr name>\0<encoded stat>\0<acl rendered text>\0<xattr data>
+ * LNK: <xattr name>\0<encoded stat>\0<target xattr name>\0
+ */
+ /* attribute name and length */
+ name = bp;
+ len = strlen (bp);
+ bp += len + 1;
+
+ /* attribute encoded stat */
+ attribs = bp;
+ len = strlen (bp);
+ bp += len + 1;
+ /* decode it */
+ decode_stat(attribs, &st, sizeof(st), &inum);
+
+ /* acltext and link target name goes here */
+ acltext = lntarget = bp;
+ len = strlen (bp);
+ /* now 'bp' should have a xattr data */
+ bp += len + 1;
+
+ /*
+ * Open the xattr on which to restore the xattrs read-only.
+ */
+ if ((attrdirfd = attropen(jcr->last_fname, ".", O_RDONLY)) < 0){
+ berrno be;
+
+ Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"), jcr->last_fname, be.bstrerror());
+ Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n", jcr->last_fname, be.bstrerror());
+ rc = bRC_XACL_error;
+ goto bail_out;
+ }
+
+ switch (st.st_mode & S_IFMT){
+ case S_IFREG:
+ if (inum != 0){
+ /* it is a linked attribute, perform a link operation */
+ unlinkat(attrdirfd, name, 0);
+ if (link(lntarget, name) < 0){
+ berrno be;
+
+ Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"), name, lntarget, jcr->last_fname, be.bstrerror());
+ Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n", name, lntarget, jcr->last_fname, be.bstrerror());
+ rc = bRC_XACL_error;
+ goto bail_out;
+ }
+ goto bail_out;
+ } else {
+ if (!extended){
+ unlinkat(attrdirfd, name, 0);
+ }
+ if ((attrfd = openat(attrdirfd, name, O_CREAT|O_RDWR)) < 0){
+ berrno be;
+
+ Mmsg3(jcr->errmsg, _("Unable to open attribute \"%s\" at file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "Unable to open attribute \"%s\" at file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
+ rc = bRC_XACL_error;
+ goto bail_out;
+ }
+ /* restore any data if are available */
+ if (st.st_size > 0){
+ cnt = write (attrfd, bp, length - (bp - content) );
+ if (cnt < 0){
+ berrno be;
+
+ Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
+ rc = bRC_XACL_error;
+ goto bail_out;
+ }
+ }
+ }
+ break;
+ case S_IFDIR:
+ /* if it is a current dir ob file then we can restore acl data only */
+ if (bstrcmp(name, ".")){
+ break;
+ }
+ default:
+ Mmsg2(jcr->errmsg, _("Unsupported xattr type %s on file \"%s\"\n"), name, jcr->last_fname);
+ Dmsg2(100, "Unsupported xattr type %s on file \"%s\"\n", name, jcr->last_fname);
+ goto bail_out;
+ }
+
+ /* file data restored, so setup permissions and acl data */
+ if (!extended){
+ if (fchownat(attrdirfd, name, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0){
+ berrno be;
+
+ switch (errno){
+ case EINVAL:
+ case ENOENT:
+ break;
+ default:
+ Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
+ rc = bRC_XACL_error;
+ }
+ goto bail_out;
+ }
+ }
+
+#ifdef HAVE_ACL
+ if (strlen(acltext)){
+ rc = os_set_xattr_acl(jcr, attrfd, name, acltext);
+ if (rc != bRC_XACL_ok){
+ goto bail_out;
+ }
+ }
+#endif /* HAVE_ACL */
+
+ /* now restore a access and modification time - only for standard attribute */
+ if (!extended){
+ times[0].tv_sec = st.st_atime;
+ times[0].tv_usec = 0;
+ times[1].tv_sec = st.st_mtime;
+ times[1].tv_usec = 0;
+
+ if (futimesat(attrdirfd, name, times) < 0){
+ berrno be;
+
+ Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"), name, jcr->last_fname, be.bstrerror());
+ Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n", name, jcr->last_fname, be.bstrerror());
+ rc = bRC_XACL_error;
+ goto bail_out;
+ }
+ }
+
+bail_out:
+ if (attrfd != 0){
+ close(attrfd);
+ }
+ if (attrdirfd != 0){
+ close(attrdirfd);
+ }
+ return rc;
+};
+
+#endif /* HAVE_SUN_OS */
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+ */
+/**
+ * Major refactoring of ACL and XATTR code written by:
+ *
+ * Radosław Korzeniewski, MMXVI
+ * radoslaw@korzeniewski.net, radekk@inteos.pl
+ * Inteos Sp. z o.o. http://www.inteos.pl/
+ *
+ */
+
+#ifndef __XACL_Solaris_H_
+#define __XACL_Solaris_H_
+
+#if defined(HAVE_SUN_OS)
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#else
+#error "configure failed to detect availability of sys/acl.h"
+#endif
+
+#ifdef HAVE_SYS_ATTR_H
+#include <sys/attr.h>
+#endif
+
+/*
+ *
+ */
+#if defined(HAVE_EXTENDED_ACL)
+#if !defined(_SYS_ACL_IMPL_H)
+typedef enum acl_type {
+ ACLENT_T = 0,
+ ACE_T = 1
+} acl_type_t;
+#endif
+
+/*
+ *
+ */
+extern "C" {
+int acl_type(acl_t *);
+char *acl_strerror(int);
+};
+#endif
+
+/*
+ * Cache structure in alist
+ */
+struct XACL_Solaris_Cache {
+ ino_t inode;
+ char * name;
+};
+
+/*
+ *
+ *
+ */
+class XACL_Solaris : public XACL {
+private:
+ alist * cache;
+ bRC_XACL os_backup_acl (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL os_restore_acl (JCR *jcr, int stream, char *content, uint32_t length);
+ bRC_XACL os_backup_xattr (JCR *jcr, FF_PKT *ff_pkt);
+ bRC_XACL os_restore_xattr (JCR *jcr, int stream, char *content, uint32_t length);
+ bRC_XACL os_get_acl(JCR *jcr, int *stream);
+ bRC_XACL os_set_acl(JCR *jcr, int stream, char *content, uint32_t length);
+ bRC_XACL os_get_xattr_names (JCR *jcr, POOLMEM **list, uint32_t *length);
+ bRC_XACL os_get_xattr_value (JCR *jcr, char * name, char ** pvalue, uint32_t * plen);
+ bRC_XACL os_set_xattr (JCR *jcr, bool extended, char *content, uint32_t length);
+ bRC_XACL os_get_xattr_acl(JCR *jcr, int fd, char **buffer);
+ bRC_XACL os_set_xattr_acl(JCR *jcr, int fd, char *name, char *acltext);
+ /* requires acl.h available */
+ bRC_XACL check_xacltype (JCR *jcr, int name);
+ inline char * find_xattr_cache(JCR *jcr, ino_t ino, char * name);
+ inline void delete_xattr_cache();
+public:
+ XACL_Solaris ();
+ ~XACL_Solaris ();
+};
+
+#endif /* HAVE_SUN_OS */
+
+#endif /* __XACL_Solaris_H_ */
+++ /dev/null
-/*
- Bacula(R) - The Network Backup Solution
-
- Copyright (C) 2000-2015 Kern Sibbald
- Copyright (C) 2008-2014 Free Software Foundation Europe e.V.
-
- The original author of Bacula is Kern Sibbald, with contributions
- from many others, a complete list can be found in the file AUTHORS.
-
- You may use this file and others of this release according to the
- license defined in the LICENSE file, which includes the Affero General
- Public License, v3.0 ("AGPLv3") and some additional permissions and
- terms pursuant to its AGPLv3 Section 7.
-
- This notice must be preserved when any source code is
- conveyed and/or propagated.
-
- Bacula(R) is a registered trademark of Kern Sibbald.
-*/
-/*
- * 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:
- * - AIX (Extended Attributes)
- * - Darwin (Extended Attributes)
- * - FreeBSD (Extended Attributes)
- * - GNU HURD (Extended Attributes)
- * - IRIX (Extended Attributes)
- * - Linux (Extended Attributes)
- * - NetBSD (Extended Attributes)
- * - OpenBSD (Extended Attributes)
- * (As it seems either they never implemented xattr or they are removed
- * the support as it stated it was in version 3.1 but the current syscall
- * tabled shows the extattr_ functions are not implemented. So as such we
- * might eventually support xattr on OpenBSD when they implemented them using
- * the same interface as FreeBSD and NetBSD.
- * - Solaris (Extended Attributes and Extensible Attributes)
- * - Tru64 (Extended Attributes)
- *
- * Written by Marco van Wieringen, November 2008
- * Major overhaul January 2012 + June 2012
- * Simplfied by Kern Sibbald, June 2015
- */
-
-#include "bacula.h"
-#include "filed.h"
-
-#ifndef HAVE_XATTR
-/*
- * Entry points when compiled without support for XATTRs or on an unsupported platform.
- */
-bool backup_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- Jmsg(jcr, M_FATAL, 0, "XATTR backup requested but not configured in Bacula.\n");
- return false;
-}
-
-bxattr_rtn_code restore_xattr_streams(JCR *jcr, int stream, char *content,
- uint32_t content_length)
-{
- return bxattr_rtn_fatal;
-}
-#else
-/*
- * Send a XATTR stream to the SD.
- */
-static bxattr_rtn_code send_xattr_stream(JCR *jcr, int stream)
-{
- BSOCK *sd = jcr->store_bsock;
- POOLMEM *msgsave;
-
-#ifdef FD_NO_SEND_TEST
- return bxattr_rtn_ok;
-#endif
-
- /*
- * Sanity check
- */
- if (jcr->xattr_ctx->content_length <= 0) {
- return bxattr_rtn_ok;
- }
-
- /*
- * 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 bxattr_rtn_fatal;
- }
-
- /*
- * Send the buffer to the storage deamon
- */
- Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_ctx->content);
- msgsave = sd->msg;
- sd->msg = jcr->xattr_ctx->content;
- sd->msglen = jcr->xattr_ctx->content_length;
- 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 bxattr_rtn_fatal;
- }
-
- 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 bxattr_rtn_fatal;
- }
- Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
- return bxattr_rtn_ok;
-}
-
-/*
- * First some generic functions for OSes that use the same xattr encoding scheme.
- * Currently for all OSes except for Solaris.
- */
-#ifndef HAVE_SUN_OS
-static void xattr_drop_internal_table(alist *xattr_value_list)
-{
- xattr_t *current_xattr;
-
- if (!xattr_value_list) {
- return;
- }
- /* Walk the list of xattrs and free allocated memory. */
- foreach_alist(current_xattr, xattr_value_list) {
- if (current_xattr->magic != XATTR_MAGIC) {
- continue;
- }
- if (current_xattr->name) {
- free(current_xattr->name);
- }
- if (current_xattr->value && current_xattr->value_length > 0) {
- free(current_xattr->value);
- }
- free(current_xattr);
- }
- delete xattr_value_list;
-}
-
-/*
- * The xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
- * which encodes one or more xattr_t structures.
- *
- * The Serialized stream consists of the following elements:
- * magic - A magic string which makes it easy to detect any binary incompatabilites
- * name_length - The length of the following xattr name
- * name - The name of the extended attribute
- * value_length - The length of the following xattr data
- * value - The actual content of the extended attribute
- *
- * This is repeated 1 or more times.
- *
- */
-static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len,
- alist *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_ctx->content =
- check_pool_memory_size(jcr->xattr_ctx->content, expected_serialize_len + 10);
- ser_begin(jcr->xattr_ctx->content, expected_serialize_len + 10);
-
- /*
- * Walk the list of xattrs and serialize the data.
- */
- foreach_alist(current_xattr, xattr_value_list) {
- if (current_xattr->magic != XATTR_MAGIC) {
- continue; /* Don't write invalid xattr */
- }
-
- 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);
- if (current_xattr->value_length > 0 && current_xattr->value) {
- ser_bytes(current_xattr->value, current_xattr->value_length);
- Dmsg3(100, "Backup xattr named %s, value %*s\n",
- current_xattr->name, current_xattr->value, current_xattr->value);
- } else {
- Dmsg1(100, "Backup empty xattr named %s\n", current_xattr->name);
- }
- }
-
- ser_end(jcr->xattr_ctx->content, expected_serialize_len + 10);
- jcr->xattr_ctx->content_length = ser_length(jcr->xattr_ctx->content);
- return jcr->xattr_ctx->content_length;
-}
-
-static bxattr_rtn_code unserialize_xattr_stream(JCR *jcr,
- char *content,
- uint32_t content_length,
- alist *xattr_value_list)
-{
- unser_declare;
- xattr_t *current_xattr;
-
- /*
- * Restore the stream and call restore_xattr_on_file for each extended attribute.
- *
- * Start unserializing the data. We keep on looping while we have not
- * unserialized all bytes in the stream.
- */
- unser_begin(content, content_length);
- while (unser_length(content) < content_length) {
- /*
- * 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.
- */
- current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
- unser_uint32(current_xattr->magic);
- if (current_xattr->magic != XATTR_MAGIC) {
- Mmsg1(jcr->errmsg, _("Invalid xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- free(current_xattr);
- return bxattr_rtn_error;
- }
-
- /*
- * Decode the valuepair. First decode the length of the name.
- */
- unser_uint32(current_xattr->name_length);
- if (current_xattr->name_length == 0) {
- Mmsg1(jcr->errmsg, _("Invalid xattr stream, xattr name length <= 0 on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- free(current_xattr);
- return bxattr_rtn_error;
- }
-
- /*
- * Allocate room for the name and decode its content.
- */
- current_xattr->name = (char *)malloc(current_xattr->name_length + 1);
- unser_bytes(current_xattr->name, current_xattr->name_length);
-
- /*
- * The xattr_name needs to be null terminated.
- */
- current_xattr->name[current_xattr->name_length] = '\0';
-
- /*
- * Decode the value length.
- */
- unser_uint32(current_xattr->value_length);
-
- if (current_xattr->value_length > 0) {
- /*
- * Allocate room for the value and decode its content.
- */
- current_xattr->value = (char *)malloc(current_xattr->value_length);
- unser_bytes(current_xattr->value, current_xattr->value_length);
-
- Dmsg3(100, "Restoring xattr named %s, value %*s\n",
- current_xattr->name, current_xattr->value, current_xattr->value);
- } else {
- current_xattr->value = NULL;
- Dmsg1(100, "Restoring empty xattr named %s\n", current_xattr->name);
- }
-
- xattr_value_list->append(current_xattr);
- }
-
- unser_end(content, content_length);
- return bxattr_rtn_ok;
-}
-#endif
-
-/*
- * This is a supported OS, See what kind of interface we should use.
- */
-#if defined(HAVE_AIX_OS)
-
-#if (!defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)) || \
- (!defined(HAVE_GETEA) && !defined(HAVE_LGETEA)) || \
- (!defined(HAVE_SETEA) && !defined(HAVE_LSETEA))
-#error "Missing full support for the Extended Attributes (EA) functions."
-#endif
-
-#ifdef HAVE_SYS_EA_H
-#include <sys/ea.h>
-#else
-#error "Missing sys/ea.h header file"
-#endif
-
-/*
- * Define the supported XATTR streams for this OS
- */
-static int os_default_xattr_streams[1] = {
- STREAM_XATTR_AIX
-};
-
-/*
- * Fallback to the non l-functions when those are not available.
- */
-#if defined(HAVE_GETEA) && !defined(HAVE_LGETEA)
-#define lgetea getea
-#endif
-#if defined(HAVE_SETEA) && !defined(HAVE_LSETEA)
-#define lsetea setea
-#endif
-#if defined(HAVE_LISTEA) && !defined(HAVE_LLISTEA)
-#define llistea listea
-#endif
-
-static bxattr_rtn_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- char *bp;
- bool skip_xattr;
- char *xattr_list = NULL;
- int cnt, xattr_count = 0;
- uint32_t name_length;
- int32_t xattr_list_len, xattr_value_len;
- uint32_t expected_serialize_len = 0;
- xattr_t *current_xattr;
- alist *xattr_value_list = NULL;
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- /*
- * First get the length of the available list with extended attributes.
- */
- xattr_list_len = llistea(jcr->last_fname, NULL, 0);
- if (xattr_list_len < 0) {
- berrno be;
- if (errno == ENOENT || errno == EFORMAT) {
- retval = bxattr_rtn_ok;
- } else if (errno == ENOTSUP) {
- /*
- * If the filesystem reports it doesn't support XATTRs we clear the
- * BXATTR_FLAG_SAVE_NATIVE flag so we skip XATTR saves on all other files
- * on the same filesystem. The BXATTR_FLAG_SAVE_NATIVE flags gets sets again
- * when we change from one filesystem to an other.
- */
- jcr->xattr_ctx->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
- retval = bxattr_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("XATTR llistea error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- }
- goto get_out;
- } else if (xattr_list_len == 0) {
- retval = bxattr_rtn_ok;
- goto get_out;
- }
-
- /*
- * Allocate room for the extented attribute list.
- */
- xattr_list = (char *)malloc(xattr_list_len + 1);
- memset(xattr_list, 0, xattr_list_len + 1);
-
- /*
- * Get the actual list of extended attributes names for a file.
- */
- xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
- if (xattr_list_len < 0) {
- berrno be;
- if (errno == ENOENT || errno == EFORMAT) {
- retval = bxattr_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("XATTR llistea error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- }
- goto get_out;
- }
- xattr_list[xattr_list_len] = '\0';
-
- /*
- * Walk the list of extended attributes names and retrieve the data.
- * We already count the bytes needed for serializing the stream later on.
- */
- for (bp = xattr_list; (bp - xattr_list) + 1 < xattr_list_len;
- bp = strchr(bp, '\0') + 1) {
- skip_xattr = false;
-
- /*
- * We want to skip certain xattrs which start with a 0xF8 character on AIX.
- */
- if (*bp == 0xF8) {
- skip_xattr = true;
- }
-
- name_length = strlen(bp);
- if (skip_xattr || name_length == 0) {
- Dmsg1(100, "Skipping xattr named %s\n", bp);
- continue;
- }
-
- /*
- * First see how long the value is for the extended attribute.
- */
- xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
- if (xattr_value_len < 0) {
- berrno be;
- if (errno == ENOENT || errno == EFORMAT) {
- retval = bxattr_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("XATTR lgetea error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- }
- goto get_out;
- }
-
- /*
- * Each xattr valuepair starts with a magic so we can restore it easier.
- */
- current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
- memset(current_xattr, 0, sizeof(xattr_t));
- current_xattr->magic = XATTR_MAGIC;
- expected_serialize_len += sizeof(current_xattr->magic);
-
- /*
- * Allocate space for storing the name.
- */
- current_xattr->name_length = name_length;
- current_xattr->name = (char *)malloc(current_xattr->name_length);
- memcpy(current_xattr->name, bp, current_xattr->name_length);
-
- expected_serialize_len += sizeof(current_xattr->name_length) +
- current_xattr->name_length;
-
- if (xattr_value_len == 0) {
- current_xattr->value = NULL;
- current_xattr->value_length = 0;
- expected_serialize_len += sizeof(current_xattr->value_length);
- } else {
- /*
- * Allocate space for storing the value.
- */
- current_xattr->value = (char *)malloc(xattr_value_len);
- memset(current_xattr->value, 0, xattr_value_len);
-
- xattr_value_len = lgetea(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
- if (xattr_value_len < 0) {
- berrno be;
- if (errno == ENOENT || errno == EFORMAT) {
- retval = bxattr_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("XATTR lgetea error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- }
-
- /*
- * Default failure path out when retrieval of attr fails.
- */
- free(current_xattr->value);
- free(current_xattr->name);
- free(current_xattr);
- goto get_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;
- }
-
- if (xattr_value_list == NULL) {
- xattr_value_list = New(alist(10, not_owned_by_alist));
- }
-
- xattr_value_list->append(current_xattr);
- xattr_count++;
-
- /*
- * Protect ourself against things getting out of hand.
- */
- if (expected_serialize_len >= MAX_XATTR_LENGTH) {
- Mmsg2(jcr->errmsg,
- _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
- jcr->last_fname, MAX_XATTR_LENGTH);
- goto get_out;
- }
- }
-
- free(xattr_list);
- xattr_list = (char *)NULL;
-
- /*
- * If we found any xattr send them to the SD.
- */
- if (xattr_count > 0) {
- /* Serialize the datastream. */
- if (serialize_xattr_stream(jcr, expected_serialize_len,
- xattr_value_list) < expected_serialize_len) {
- Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Send the datastream to the SD.
- */
- retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
- } else {
- retval = bxattr_rtn_ok;
- }
-
-get_out:
- if (xattr_list != NULL) {
- free(xattr_list);
- }
- if (xattr_value_list != NULL) {
- xattr_drop_internal_table(xattr_value_list);
- }
-
- return retval;
-}
-
-static bxattr_rtn_code aix_restore_xattr_streams(JCR *jcr, int stream, char *content,
- uint32_t content_length)
-{
- xattr_t *current_xattr;
- alist *xattr_value_list;
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- xattr_value_list = New(alist(10, not_owned_by_alist));
-
- if (unserialize_xattr_stream(jcr, content, content_length,
- xattr_value_list) != bxattr_rtn_ok) {
- goto get_out;
- }
-
- foreach_alist(current_xattr, xattr_value_list) {
- if (lsetea(jcr->last_fname, current_xattr->name, current_xattr->value,
- current_xattr->value_length, 0) != 0) {
- berrno be;
- switch (errno) {
- case ENOENT:
- case EFORMAT:
- break;
- case ENOTSUP:
- /*
- * If the filesystem reports it doesn't support XATTRs we clear
- * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
- * on all other files on the same filesystem. The
- * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
- * change from one filesystem to an other.
- */
- jcr->xattr_ctx->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
- /* Failback wanted */
- default:
- MmsgD2(100, jcr->errmsg,
- _("XATTR lsetea error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- break;
- }
- goto get_out;
- }
- }
- retval = bxattr_rtn_ok;
-
-get_out:
- xattr_drop_internal_table(xattr_value_list);
-
- return retval;
-}
-
-/*
- * Function pointers to the build and restore function to use for these xattrs.
- */
-static bxattr_rtn_code (*os_backup_xattr_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- aix_xattr_build_streams;
-static bxattr_rtn_code (*os_restore_xattr_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- aix_restore_xattr_streams;
-
-#elif defined(HAVE_IRIX_OS)
-
-#include <sys/attributes.h>
-
-/*
- * Define the supported XATTR streams for this OS
- */
-static int os_default_xattr_streams[1] = {
- STREAM_XATTR_IRIX
-};
-static const char *xattr_acl_skiplist[1] = {
- NULL
-};
-static const char *xattr_skiplist[1] = {
- NULL
-};
-
-struct xattr_naming_space {
- const char *name;
- int flags;
-};
-
-static xattr_naming_space xattr_naming_spaces[] = {
- {
- "user.",
- ATTR_DONTFOLLOW
- }, {
- "root.",
- ATTR_ROOT | ATTR_DONTFOLLOW
- }, {
- NULL,
- 0
- }
-};
-
-static bxattr_rtn_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- char dummy[32];
- int cnt, length, xattr_count = 0;
- attrlist_cursor_t cursor;
- attrlist_t *attrlist;
- attrlist_ent_t *attrlist_ent;
- xattr_t *current_xattr;
- alist *xattr_value_list = NULL;
- uint32_t expected_serialize_len = 0;
- bxattr_rtn_code retval = bxattr_rtn_error;
- POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
-
- for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
- memset(&cursor, 0, sizeof(attrlist_cursor_t));
- for ( ;; } {
- if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
- xattr_naming_spaces[cnt].flags, &cursor) != 0) {
- berrno be;
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg2(jcr->errmsg, _("XATTR attr_list error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
- attrlist = (attrlist_t *)xattrbuf;
-
- /*
- * Walk the available attributes.
- */
- for (cnt = 0; cnt < attrlist->al_count; cnt++) {
- attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
-
- /*
- * First determine if we can retrieve the xattr and how big it really is.
- */
- length = sizeof(dummy);
- if (attr_get(jcr->last_fname, attrlist_ent->a_name, dummy,
- &length, xattr_naming_spaces[cnt].flags) != 0) {
- berrno be;
- switch (errno) {
- case ENOENT:
- case ENOATTR:
- retval = bxattr_rtn_ok;
- goto get_out;
- case E2BIG:
- /*
- * Size of the xattr is bigger then the 32 bytes dummy which is
- * likely. As length now contains its actual length we can allocate
- * a properly size buffer for the real retrieval.
- */
- break;
- default:
- Mmsg2(jcr->errmsg, _("XATTR attr_list error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
- /*
- * Each xattr valuepair starts with a magic so we can restore it easier.
- */
- current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
- memset(current_xattr, 0, sizeof(xattr_t));
- current_xattr->magic = XATTR_MAGIC;
- expected_serialize_len += sizeof(current_xattr->magic);
-
- /*
- * Allocate space for storing the name.
- * We store the name as <naming_space_name><xattr_name>
- */
- current_xattr->name_length = strlen(xattr_naming_spaces[cnt].name) +
- strlen(attrlist_ent->a_name) + 1;
- current_xattr->name = (char *)malloc(current_xattr->name_length);
- bsnprintf(current_xattr->name, current_xattr->name_length, "%s%s",
- xattr_naming_spaces[cnt].name, attrlist_ent->a_name);
-
- expected_serialize_len += sizeof(current_xattr->name_length) +
- current_xattr->name_length;
-
- current_xattr->value_length = length;
- current_xattr->value = (char *)malloc(current_xattr->value_length);
-
- /*
- * Retrieve the actual value of the xattr.
- */
- if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
- &length, xattr_naming_spaces[cnt].flags) != 0) {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- case ENOATTR:
- retval = bxattr_rtn_ok;
- break;
- case E2BIG:
- /*
- * The buffer for the xattr isn't big enough. the value of
- * current_xattr->value_length is updated with the actual size
- * of the xattr. So we free the old buffer and create a new one
- * and try again. Normally this cannot happen as we size the
- * buffer using a call to attr_get before but in case of an
- * race condition it might happen.
- */
- free(current_xattr->value);
- current_xattr->value = (char *)malloc(length);
- if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
- &length, xattr_naming_spaces[cnt].flags) != 0) {
- switch (errno) {
- case ENOENT:
- case ENOATTR:
- retval = bxattr_rtn_ok;
- break;
- default:
- Mmsg2(jcr->errmsg,
- _("attr_list error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror(errno));
- Dmsg2(100, "attr_list error file=%s ERR=%s\n",
- jcr->last_fname, be.bstrerror());
- break;
- }
- } else {
- goto ok_continue;
- }
- break;
- default:
- Mmsg2(jcr->errmsg, _("XATTR attr_list error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- break;
- }
-
- /*
- * Default failure path out when retrieval of attr fails.
- */
- free(current_xattr->value);
- free(current_xattr->name);
- free(current_xattr);
- goto get_out;
- }
-
-ok_continue:
- current_xattr->value_length = length;
- expected_serialize_len += sizeof(current_xattr->value_length) +
- current_xattr->value_length;
-
- if (xattr_value_list == NULL) {
- xattr_value_list = New(alist(10, not_owned_by_alist));
- }
-
- xattr_value_list->append(current_xattr);
- xattr_count++;
-
- /*
- * Protect ourself against things getting out of hand.
- */
- if (expected_serialize_len >= MAX_XATTR_LENGTH) {
- Mmsg2(jcr->errmsg,
- _("XATTR stream on file \"%s\" exceeds maximum size of %d bytes\n"),
- jcr->last_fname, MAX_XATTR_LENGTH);
- goto get_out;
- }
- }
-
- /*
- * See if there are more attributes available for a next run of attr_list.
- */
- if (attrlist->al_more == 0) {
- break;
- }
- }
- }
-
- /*
- * If we found any xattr send them to the SD.
- */
- if (xattr_count > 0) {
- /* Serialize the XATTR */
- if (serialize_xattr_stream(jcr, expected_serialize_len,
- xattr_value_list) < expected_serialize_len) {
- Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /* Send the XATTR to the SD. */
- retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
- } else {
- retval = bxattr_rtn_ok;
- }
-
-get_out:
- free_pool_memory(xattrbuf);
-
- if (xattr_value_list != NULL) {
- xattr_drop_internal_table(xattr_value_list);
- }
-
- return retval;
-}
-
-static bxattr_rtn_code irix_restore_xattr_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
- char *bp;
- int cnt, cmp_size, name_space_index, flags;
- xattr_t *current_xattr;
- alist *xattr_value_list;
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- xattr_value_list = New(alist(10, not_owned_by_alist));
-
- if (unserialize_xattr_stream(jcr,
- content,
- content_length,
- xattr_value_list) != bxattr_rtn_ok) {
- goto get_out;
- }
-
- foreach_alist(current_xattr, xattr_value_list) {
- /*
- * See to what namingspace this xattr belongs to.
- */
- name_space_index = 0;
- for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
- cmp_size = strlen(xattr_naming_spaces[cnt].name);
- if (!strncasecmp(current_xattr->name,
- xattr_naming_spaces[cnt].name,
- cmp_size)) {
- name_space_index = cnt;
- break;
- }
- }
-
- /*
- * If we got a xattr that doesn't belong to an valid namespace complain.
- */
- if (name_space_index == 0) {
- Mmsg2(jcr->errmsg,
- _("Received invalid xattr named %s on file \"%s\"\n"),
- current_xattr->name, jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Restore the xattr first try to create the attribute from scratch.
- */
- flags = xattr_naming_spaces[name_space_index].flags | ATTR_CREATE;
- bp = strchr(current_xattr->name, '.');
- if (attr_set(jcr->last_fname, ++bp, current_xattr->value,
- current_xattr->value_length, flags) != 0) {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
- case EEXIST:
- /*
- * The xattr already exists we need to replace it.
- */
- flags = xattr_naming_spaces[name_space_index].flags | ATTR_REPLACE;
- if (attr_set(jcr->last_fname, bp, current_xattr->value,
- current_xattr->value_length, flags) != 0) {
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror(errno));
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
- break;
- default:
- Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
- }
-
- retval = bxattr_rtn_ok;
-
-get_out:
- xattr_drop_internal_table(xattr_value_list);
-
- return retval;
-}
-
-/*
- * Function pointers to the build and restore function to use for these xattrs.
- */
-static bxattr_rtn_code (*os_backup_xattr_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- irix_xattr_build_streams;
-static bxattr_rtn_code (*os_restore_xattr_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- irix_restore_xattr_streams;
-
-#elif defined(HAVE_DARWIN_OS) || \
- defined(HAVE_LINUX_OS) || \
- defined(HAVE_HURD_OS)
-
-#if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
- (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
- (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
-#error "Missing full support for the XATTR functions."
-#endif
-
-#ifdef HAVE_SYS_XATTR_H
-#include <sys/xattr.h>
-#else
-#error "Missing sys/xattr.h header file"
-#endif
-
-/*
- * Define the supported XATTR streams for this OS
- */
-#if defined(HAVE_DARWIN_OS)
-static int os_default_xattr_streams[1] = {
- STREAM_XATTR_DARWIN
-};
-static const char *xattr_acl_skiplist[2] = {
- "com.apple.system.Security",
- NULL
-};
-static const char *xattr_skiplist[3] = {
- "com.apple.system.extendedsecurity",
- "com.apple.ResourceFork",
- NULL
-};
-#elif defined(HAVE_LINUX_OS)
-static int os_default_xattr_streams[1] = {
- STREAM_XATTR_LINUX
-};
-static const char *xattr_acl_skiplist[3] = {
- "system.posix_acl_access",
- "system.posix_acl_default",
- NULL
-};
-static const char *xattr_skiplist[1] = {
- NULL
-};
-#elif defined(HAVE_HURD_OS)
-static int os_default_xattr_streams[1] = {
- STREAM_XATTR_HURD
-};
-static const char *xattr_acl_skiplist[1] = {
- NULL
-};
-static const char *xattr_skiplist[1] = {
- NULL
-};
-#endif
-
-/*
- * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
- * listxattr, getxattr and setxattr with an extra options argument
- * which mimics the l variants of the functions when we specify
- * XATTR_NOFOLLOW as the options value.
- */
-#if defined(HAVE_DARWIN_OS)
- #define llistxattr(path, list, size) \
- listxattr((path), (list), (size), XATTR_NOFOLLOW)
- #define lgetxattr(path, name, value, size) \
- getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
- #define lsetxattr(path, name, value, size, flags) \
- setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
-#else
- /*
- * Fallback to the non l-functions when those are not available.
- */
- #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
-#endif
-
-static bxattr_rtn_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- char *bp;
- bool skip_xattr;
- char *xattr_list = NULL;
- int cnt, xattr_count = 0;
- uint32_t name_length;
- int32_t xattr_list_len,
- xattr_value_len;
- uint32_t expected_serialize_len = 0;
- xattr_t *current_xattr;
- alist *xattr_value_list = NULL;
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- /*
- * First get the length of the available list with extended attributes.
- */
- xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
- switch (xattr_list_len) {
- case -1: {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
- case BXATTR_ENOTSUP:
- /*
- * If the filesystem reports it doesn't support XATTRs we clear
- * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
- * on all other files on the same filesystem. The
- * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
- * change from one filesystem to an other.
- */
- jcr->xattr_ctx->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- break;
- }
- case 0:
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- break;
- }
-
- /*
- * Allocate room for the extented attribute list.
- */
- xattr_list = (char *)malloc(xattr_list_len + 1);
- memset(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;
- if (errno == ENOENT) {
- retval = bxattr_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- }
- goto get_out;
- }
- xattr_list[xattr_list_len] = '\0';
-
- /*
- * Walk the list of extended attributes names and retrieve the data.
- * We already count the bytes needed for serializing the stream later on.
- */
- for (bp = xattr_list;
- (bp - xattr_list) + 1 < xattr_list_len;
- bp = strchr(bp, '\0') + 1) {
- skip_xattr = false;
-
- /*
- * On some OSes 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) {
- for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
- if (bstrcmp(bp, xattr_acl_skiplist[cnt])) {
- skip_xattr = true;
- break;
- }
- }
- }
-
- /*
- * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
- */
- if (!skip_xattr) {
- for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
- if (bstrcmp(bp, xattr_skiplist[cnt])) {
- skip_xattr = true;
- break;
- }
- }
- }
-
- name_length = strlen(bp);
- if (skip_xattr || name_length == 0) {
- Dmsg1(100, "Skipping xattr named %s\n", bp);
- continue;
- }
-
- /*
- * 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;
- if (errno == ENOENT) {
- retval = bxattr_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- }
- goto get_out;
- }
-
- /*
- * Each xattr valuepair starts with a magic so we can restore it easier.
- */
- current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
- current_xattr->magic = XATTR_MAGIC;
- current_xattr->value = NULL;
- expected_serialize_len += sizeof(current_xattr->magic);
-
- /*
- * Allocate space for storing the name.
- */
- current_xattr->name_length = name_length;
- current_xattr->name = (char *)malloc(current_xattr->name_length);
- memcpy(current_xattr->name, bp, current_xattr->name_length);
-
- expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
-
- switch (xattr_value_len) {
- case 0:
- current_xattr->value = NULL;
- current_xattr->value_length = 0;
- expected_serialize_len += sizeof(current_xattr->value_length);
- break;
- default:
- /*
- * Allocate space for storing the value.
- */
- current_xattr->value = (char *)malloc(xattr_value_len);
- memset(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;
-
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- break;
- default:
- Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- break;
- }
-
- /*
- * Default failure path out when retrieval of attr fails.
- */
- free(current_xattr->value);
- free(current_xattr->name);
- free(current_xattr);
- goto get_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;
- break;
- }
-
- if (xattr_value_list == NULL) {
- xattr_value_list = New(alist(10, not_owned_by_alist));
- }
-
- xattr_value_list->append(current_xattr);
- xattr_count++;
-
- /*
- * Protect ourself against things getting out of hand.
- */
- if (expected_serialize_len >= MAX_XATTR_LENGTH) {
- Mmsg2(jcr->errmsg,
- _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
- jcr->last_fname, MAX_XATTR_LENGTH);
- goto get_out;
- }
- }
-
- free(xattr_list);
- xattr_list = (char *)NULL;
-
- /*
- * If we found any xattr send them to the SD.
- */
- if (xattr_count > 0) {
- /*
- * Serialize the datastream.
- */
- if (serialize_xattr_stream(jcr, expected_serialize_len,
- xattr_value_list) < expected_serialize_len) {
- Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Send the datastream to the SD.
- */
- retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
- } else {
- retval = bxattr_rtn_ok;
- }
-
-get_out:
- if (xattr_list != NULL) {
- free(xattr_list);
- }
- if (xattr_value_list != NULL) {
- xattr_drop_internal_table(xattr_value_list);
- }
-
- return retval;
-}
-
-static bxattr_rtn_code generic_restore_xattr_streams(JCR *jcr, int stream,
- char *content,
- uint32_t content_length)
-{
- xattr_t *current_xattr;
- alist *xattr_value_list;
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- xattr_value_list = New(alist(10, not_owned_by_alist));
-
- if (unserialize_xattr_stream(jcr, content, content_length,
- xattr_value_list) != bxattr_rtn_ok) {
- goto get_out;
- }
-
- foreach_alist(current_xattr, xattr_value_list) {
- if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
- berrno be;
- if (errno == ENOENT) {
- goto get_out;
- } else if (errno == BXATTR_ENOTSUP) {
- /*
- * If the filesystem reports it doesn't support XATTRs we clear
- * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
- * on all other files on the same filesystem. The
- * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
- * change from one filesystem to an other.
- */
- jcr->xattr_ctx->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
- }
- MmsgD2(100, jcr->errmsg,
- _("lsetxattr error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- goto get_out;
- }
- }
-
- retval = bxattr_rtn_ok;
-
-get_out:
- xattr_drop_internal_table(xattr_value_list);
- return retval;
-}
-
-/*
- * Function pointers to the build and restore functions to use for these xattrs.
- */
-static bxattr_rtn_code (*os_backup_xattr_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- generic_xattr_build_streams;
-static bxattr_rtn_code (*os_restore_xattr_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- generic_restore_xattr_streams;
-
-#elif defined(HAVE_FREEBSD_OS) || \
- defined(HAVE_NETBSD_OS) || \
- defined(HAVE_OPENBSD_OS)
-
-#if (!defined(HAVE_EXTATTR_GET_LINK) && !defined(HAVE_EXTATTR_GET_FILE)) || \
- (!defined(HAVE_EXTATTR_SET_LINK) && !defined(HAVE_EXTATTR_SET_FILE)) || \
- (!defined(HAVE_EXTATTR_LIST_LINK) && !defined(HAVE_EXTATTR_LIST_FILE)) || \
- !defined(HAVE_EXTATTR_NAMESPACE_TO_STRING) || \
- !defined(HAVE_EXTATTR_STRING_TO_NAMESPACE)
-#error "Missing full support for the extattr functions."
-#endif
-
-#ifdef HAVE_SYS_EXTATTR_H
-#include <sys/extattr.h>
-#else
-#error "Missing sys/extattr.h header file"
-#endif
-
-#ifdef HAVE_LIBUTIL_H
-#include <libutil.h>
-#endif
-
-#if !defined(HAVE_EXTATTR_GET_LINK) && defined(HAVE_EXTATTR_GET_FILE)
-#define extattr_get_link extattr_get_file
-#endif
-#if !defined(HAVE_EXTATTR_SET_LINK) && defined(HAVE_EXTATTR_SET_FILE)
-#define extattr_set_link extattr_set_file
-#endif
-#if !defined(HAVE_EXTATTR_LIST_LINK) && defined(HAVE_EXTATTR_LIST_FILE)
-#define extattr_list_link extattr_list_file
-#endif
-
-#if defined(HAVE_FREEBSD_OS)
-static int os_default_xattr_streams[1] = {
- STREAM_XATTR_FREEBSD
-};
-static int os_default_xattr_namespaces[2] = {
- EXTATTR_NAMESPACE_USER,
- EXTATTR_NAMESPACE_SYSTEM
-};
-static const char *xattr_acl_skiplist[4] = {
- "system.posix1e.acl_access",
- "system.posix1e.acl_default",
- "system.nfs4.acl",
- NULL
-};
-static const char *xattr_skiplist[1] = {
- NULL
-};
-#elif defined(HAVE_NETBSD_OS)
-static int os_default_xattr_streams[1] = {
- STREAM_XATTR_NETBSD
-};
-static int os_default_xattr_namespaces[2] = {
- EXTATTR_NAMESPACE_USER,
- EXTATTR_NAMESPACE_SYSTEM
-};
-static const char *xattr_acl_skiplist[1] = {
- NULL
-};
-static const char *xattr_skiplist[1] = {
- NULL
-};
-#elif defined(HAVE_OPENBSD_OS)
-static int os_default_xattr_streams[1] = {
- STREAM_XATTR_OPENBSD
-};
-static int os_default_xattr_namespaces[2] = {
- EXTATTR_NAMESPACE_USER,
- EXTATTR_NAMESPACE_SYSTEM
-};
-static const char *xattr_acl_skiplist[1] = {
- NULL
-};
-static const char *xattr_skiplist[1] = {
- NULL
-};
-#endif
-
-static bxattr_rtn_code bsd_backup_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- bool skip_xattr;
- char *xattr_list = NULL;
- int cnt, index, xattr_count = 0;
- int32_t xattr_list_len,
- xattr_value_len;
- uint32_t expected_serialize_len = 0;
- unsigned int namespace_index;
- int attrnamespace;
- char *current_attrnamespace = NULL;
- char current_attrname[XATTR_BUFSIZ], current_attrtuple[XATTR_BUFSIZ];
- xattr_t *current_xattr;
- alist *xattr_value_list = NULL;
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- /*
- * Loop over all available xattr namespaces.
- */
- for (namespace_index = 0;
- namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int);
- namespace_index++) {
- attrnamespace = os_default_xattr_namespaces[namespace_index];
-
- /*
- * First get the length of the available list with extended attributes.
- * If we get EPERM on system namespace, don't return error.
- * This is expected for normal users trying to archive the system
- * namespace on FreeBSD 6.2 and later. On NetBSD 3.1 and later,
- * they've decided to return EOPNOTSUPP instead.
- */
- xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
- switch (xattr_list_len) {
- case -1: {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
-#if defined(EOPNOTSUPP)
- case EOPNOTSUPP:
-#endif
- case EPERM:
- if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
- continue;
- }
- /*
- * FALLTHROUGH
- */
- default:
- Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- break;
- }
- case 0:
- continue;
- default:
- break;
- }
-
- /*
- * Allocate room for the extented attribute list.
- */
- xattr_list = (char *)malloc(xattr_list_len + 1);
- memset(xattr_list, 0, xattr_list_len + 1);
-
- /*
- * Get the actual list of extended attributes names for a file.
- */
- xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace,
- xattr_list, xattr_list_len);
- if (xattr_list_len < 0) {
- berrno be;
- if (errno == ENOENT) {
- retval = bxattr_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("extattr_list_link error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- }
- goto get_out;
- }
- xattr_list[xattr_list_len] = '\0';
-
- /*
- * Convert the numeric attrnamespace into a string representation and make
- * a private copy of that string. The extattr_namespace_to_string functions
- * returns a strdupped string which we need to free.
- */
- if (extattr_namespace_to_string(attrnamespace, ¤t_attrnamespace) != 0) {
- Mmsg2(jcr->errmsg, _("Failed to convert %d into namespace on file \"%s\"\n"),
- attrnamespace, jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Walk the list of extended attributes names and retrieve the data.
- * We already count the bytes needed for serializing the stream later on.
- */
- for (index = 0; index < xattr_list_len; index += xattr_list[index] + 1) {
- skip_xattr = false;
-
- /*
- * Print the current name into the buffer as its not null terminated
- * we need to use the length encoded in the string for copying only
- * the needed bytes.
- */
- cnt = xattr_list[index];
- if (cnt > ((int)sizeof(current_attrname) - 1)) {
- cnt = ((int)sizeof(current_attrname) - 1);
- }
- strncpy(current_attrname, xattr_list + (index + 1), cnt);
- current_attrname[cnt] = '\0';
-
- /*
- * First make a xattr tuple of the current namespace and the name of
- * the xattr. e.g. something like user.<attrname> or system.<attrname>
- */
- bsnprintf(current_attrtuple, sizeof(current_attrtuple), "%s.%s",
- current_attrnamespace, current_attrname);
-
- /*
- * On some OSes 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) {
- for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
- if (bstrcmp(current_attrtuple, xattr_acl_skiplist[cnt])) {
- skip_xattr = true;
- break;
- }
- }
- }
-
- /*
- * On some OSes we want to skip certain xattrs which are in the
- * xattr_skiplist array.
- */
- if (!skip_xattr) {
- for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
- if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
- skip_xattr = true;
- break;
- }
- }
- }
-
- if (skip_xattr) {
- Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
- continue;
- }
-
- /*
- * First see how long the value is for the extended attribute.
- */
- xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
- current_attrname, NULL, 0);
- switch (xattr_value_len) {
- case -1: {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- break;
- }
- default:
- break;
- }
-
- /*
- * Each xattr valuepair starts with a magic so we can restore it easier.
- */
- current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
- memset(current_xattr, 0, sizeof(xattr_t));
- current_xattr->magic = XATTR_MAGIC;
- expected_serialize_len += sizeof(current_xattr->magic);
-
- /*
- * Allocate space for storing the name.
- */
- current_xattr->name_length = strlen(current_attrtuple);
- current_xattr->name = (char *)malloc(current_xattr->name_length);
- memcpy(current_xattr->name, current_attrtuple, current_xattr->name_length);
-
- expected_serialize_len += sizeof(current_xattr->name_length) +
- current_xattr->name_length;
-
- switch (xattr_value_len) {
- case 0:
- current_xattr->value = NULL;
- current_xattr->value_length = 0;
- expected_serialize_len += sizeof(current_xattr->value_length);
- break;
- default:
- /*
- * Allocate space for storing the value.
- */
- current_xattr->value = (char *)malloc(xattr_value_len);
- memset(current_xattr->value, 0, xattr_value_len);
-
- xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace,
- current_attrname, current_xattr->value,
- xattr_value_len);
- if (xattr_value_len < 0) {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- break;
- default:
- Mmsg2(jcr->errmsg, _("extattr_get_link error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- break;
- }
-
- /*
- * Default failure path out when retrieval of attr fails.
- */
- free(current_xattr->value);
- free(current_xattr->name);
- free(current_xattr);
- goto get_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;
- break;
- }
-
- if (xattr_value_list == NULL) {
- xattr_value_list = New(alist(10, not_owned_by_alist));
- }
-
- xattr_value_list->append(current_xattr);
- xattr_count++;
-
- /*
- * Protect ourself against things getting out of hand.
- */
- if (expected_serialize_len >= MAX_XATTR_LENGTH) {
- Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
- jcr->last_fname, MAX_XATTR_LENGTH);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
- /*
- * Drop the local copy of the current_attrnamespace.
- */
- actuallyfree(current_attrnamespace);
- current_attrnamespace = NULL;
-
- /*
- * We are done with this xattr list.
- */
- free(xattr_list);
- xattr_list = (char *)NULL;
- }
-
- /*
- * If we found any xattr send them to the SD.
- */
- if (xattr_count > 0) {
- /*
- * Serialize the datastream.
- */
- if (serialize_xattr_stream(jcr,
- expected_serialize_len,
- xattr_value_list) < expected_serialize_len) {
- Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Send the datastream to the SD.
- */
- retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
- } else {
- retval = bxattr_rtn_ok;
- }
-
-get_out:
- if (current_attrnamespace != NULL) {
- actuallyfree(current_attrnamespace);
- }
- if (xattr_list != NULL) {
- free(xattr_list);
- }
- if (xattr_value_list != NULL) {
- xattr_drop_internal_table(xattr_value_list);
- }
-
- return retval;
-}
-
-static bxattr_rtn_code bsd_restore_xattr_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
- xattr_t *current_xattr;
- alist *xattr_value_list;
- int current_attrnamespace, cnt;
- char *attrnamespace, *attrname;
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- xattr_value_list = New(alist(10, not_owned_by_alist));
-
- if (unserialize_xattr_stream(jcr,
- content,
- content_length,
- xattr_value_list) != bxattr_rtn_ok) {
- goto get_out;
- }
-
- foreach_alist(current_xattr, xattr_value_list) {
- /*
- * Try splitting the xattr_name into a namespace and name part.
- * The splitting character is a .
- */
- attrnamespace = current_xattr->name;
- if ((attrname = strchr(attrnamespace, '.')) == (char *)NULL) {
- Mmsg2(jcr->errmsg, _("Failed to split %s into namespace and name part on file \"%s\"\n"),
- current_xattr->name, jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- *attrname++ = '\0';
-
- /*
- * Make sure the attrnamespace makes sense.
- */
- if (extattr_string_to_namespace(attrnamespace, ¤t_attrnamespace) != 0) {
- Mmsg2(jcr->errmsg, _("Failed to convert %s into namespace on file \"%s\"\n"),
- attrnamespace, jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Try restoring the extended attribute.
- */
- cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
- attrname, current_xattr->value, current_xattr->value_length);
- if (cnt < 0 || cnt != (int)current_xattr->value_length) {
- berrno be;
- if (errno == ENOENT) {
- goto get_out;
- } else {
- Mmsg2(jcr->errmsg, _("extattr_set_link error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
- }
-
- retval = bxattr_rtn_ok;
-
-get_out:
- xattr_drop_internal_table(xattr_value_list);
- return retval;
-}
-
-/*
- * Function pointers to the build and restore function to use for these xattrs.
- */
-static bxattr_rtn_code (*os_backup_xattr_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- bsd_backup_xattr_streams;
-static bxattr_rtn_code (*os_restore_xattr_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- bsd_restore_xattr_streams;
-
-#elif defined(HAVE_OSF1_OS)
-
-#if !defined(HAVE_GETPROPLIST) || \
- !defined(HAVE_GET_PROPLIST_ENTRY) || \
- !defined(HAVE_SIZEOF_PROPLIST_ENTRY) || \
- !defined(HAVE_ADD_PROPLIST_ENTRY) || \
- !defined(HAVE_SETPROPLIST)
-#error "Missing full support for the Extended Attributes functions."
-#endif
-
-#ifdef HAVE_SYS_PROPLIST_H
-#include <sys/proplist.h>
-#else
-#error "Missing sys/proplist.h header file"
-#endif
-
-/*
- * Define the supported XATTR streams for this OS
- */
-static int os_default_xattr_streams[1] = {
- STREAM_XATTR_TRU64
-};
-static const char *xattr_acl_skiplist[1] = {
- NULL
-};
-static const char *xattr_skiplist[1] = {
- NULL
-};
-
-static bxattr_rtn_code tru64_backup_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- int cnt;
- char *bp,
- *xattr_name,
- *xattr_value;
- bool skip_xattr;
- int xattr_count = 0;
- int32_t *flags,
- *xattr_value_len;
- int32_t xattr_list_len,
- xattrbuf_size,
- xattrbuf_min_size;
- uint32_t expected_serialize_len = 0;
- xattr_t *current_xattr;
- alist *xattr_value_list = NULL;
- struct proplistname_args prop_args;
- bxattr_rtn_code retval = bxattr_rtn_error;
- POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
-
- xattrbuf_size = sizeof_pool_memory(xattrbuf);
- xattrbuf_min_size = 0;
- xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
- xattrbuf, &xattrbuf_min_size);
-
- /*
- * See what xattr are available.
- */
- switch (xattr_list_len) {
- case -1: {
- berrno be;
-
- switch (errno) {
- case EOPNOTSUPP:
- /*
- * If the filesystem reports it doesn't support XATTRs we clear
- * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
- * on all other files on the same filesystem. The
- * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
- * change from one filesystem to an other.
- */
- jcr->xattr_ctx->flags &= ~BXATTR_FLAG_SAVE_NATIVE;
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- break;
- }
- case 0:
- if (xattrbuf_min_size) {
- /*
- * The buffer isn't big enough to hold the xattr data, we now have
- * a minimum buffersize so we resize the buffer and try again.
- */
- xattrbuf = check_pool_memory_size(xattrbuf, xattrbuf_min_size + 1);
- xattrbuf_size = xattrbuf_min_size + 1;
- xattr_list_len = getproplist(jcr->last_fname, 1, &prop_args, xattrbuf_size,
- xattrbuf, &xattrbuf_min_size);
- switch (xattr_list_len) {
- case -1: {
- berrno be;
-
- switch (errno) {
- default:
- Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- break;
- }
- case 0:
- /*
- * This should never happen as we sized the buffer according to the minimumsize
- * returned by a previous getproplist call. If it does happen things are fishy and
- * we are better of forgetting this xattr as it seems its list is changing at this
- * exact moment so we can never make a good backup copy of it.
- */
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- break;
- }
- } else {
- /*
- * No xattr on file.
- */
- retval = bxattr_rtn_ok;
- goto get_out;
- }
- break;
- default:
- break;
- }
-
- /*
- * Walk the list of extended attributes names and retrieve the data.
- * We already count the bytes needed for serializing the stream later on.
- */
- bp = xattrbuf;
- while (xattrbuf_size > 0) {
- /*
- * Call getproplist_entry to initialize name and value
- * pointers to entries position within buffer.
- */
- xattrbuf_size -= get_proplist_entry(&xattr_name, &flags, &xattr_value_len, &xattr_value, &bp);
-
- /*
- * On some OSes 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) {
- for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
- if (bstrcmp(xattr_name, xattr_acl_skiplist[cnt])) {
- skip_xattr = true;
- break;
- }
- }
- }
-
- /*
- * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
- */
- if (!skip_xattr) {
- for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
- if (bstrcmp(xattr_name, xattr_skiplist[cnt])) {
- skip_xattr = true;
- break;
- }
- }
- }
-
- if (skip_xattr) {
- Dmsg1(100, "Skipping xattr named %s\n", xattr_name);
- continue;
- }
-
- /*
- * Each xattr valuepair starts with a magic so we can restore it easier.
- */
- current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
- memset(current_xattr, 0, sizeof(xattr_t));
- current_xattr->magic = XATTR_MAGIC;
- expected_serialize_len += sizeof(current_xattr->magic);
-
- current_xattr->name_length = strlen(xattr_name);
- current_xattr->name = bstrdup(xattr_name);
-
- expected_serialize_len += sizeof(current_xattr->name_length) +
- current_xattr->name_length;
-
- current_xattr->value_length = *xattr_value_len;
- current_xattr->value = (char *)malloc(current_xattr->value_length);
- memcpy(current_xattr->value, xattr_value, current_xattr->value_length);
-
- expected_serialize_len += sizeof(current_xattr->value_length) +
- current_xattr->value_length;
-
- if (xattr_value_list == NULL) {
- xattr_value_list = New(alist(10, not_owned_by_alist));
- }
-
- xattr_value_list->append(current_xattr);
- xattr_count++;
-
- /*
- * Protect ourself against things getting out of hand.
- */
- if (expected_serialize_len >= MAX_XATTR_LENGTH) {
- Mmsg2(jcr->errmsg,
- _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
- jcr->last_fname, MAX_XATTR_LENGTH);
- goto get_out;
- }
- }
-
- /*
- * If we found any xattr send them to the SD.
- */
- if (xattr_count > 0) {
- /*
- * Serialize the datastream.
- */
- if (serialize_xattr_stream(jcr,
- expected_serialize_len,
- xattr_value_list) < expected_serialize_len) {
- Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Send the datastream to the SD.
- */
- retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
- } else {
- retval = bxattr_rtn_ok;
- }
-
-get_out:
- if (xattr_value_list != NULL) {
- xattr_drop_internal_table(xattr_value_list);
- }
- free_pool_memory(xattrbuf);
-
- return retval;
-}
-
-static bxattr_rtn_code tru64_restore_xattr_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
- char *bp, *xattrbuf = NULL;
- int32_t xattrbuf_size, cnt;
- xattr_t *current_xattr;
- alist *xattr_value_list;
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- xattr_value_list = New(alist(10, not_owned_by_alist));
-
- if (unserialize_xattr_stream(jcr,
- content,
- content_length,
- xattr_value_list) != bxattr_rtn_ok) {
- goto get_out;
- }
-
- /*
- * See how big the propertylist must be.
- */
- xattrbuf_size = 0;
- foreach_alist(current_xattr, xattr_value_list) {
- xattrbuf_size += sizeof_proplist_entry(current_xattr->name, current_xattr->value_length);
- }
-
- xattrbuf = (char *)malloc(xattrbuf_size);
-
- /*
- * Add all value pairs to the proplist.
- */
- cnt = 0;
- bp = xattrbuf;
- foreach_alist(current_xattr, xattr_value_list) {
- cnt = add_proplist_entry(current_xattr->name, 0, current_xattr->value_length,
- current_xattr->value, &bp);
- }
-
- /*
- * Sanity check.
- */
- if (cnt != xattrbuf_size) {
- Mmsg1(jcr->errmsg, _("Unable create proper proplist to restore xattrs on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Restore the list of extended attributes on the file.
- */
- cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
- switch (cnt) {
- case -1: {
- berrno be;
-
- switch (errno) {
- case EOPNOTSUPP:
- /*
- * If the filesystem reports it doesn't support XATTRs we clear
- * the BXATTR_FLAG_RESTORE_NATIVE flag so we skip XATTR restores
- * on all other files on the same filesystem. The
- * BXATTR_FLAG_RESTORE_NATIVE flags gets sets again when we
- * change from one filesystem to an other.
- */
- jcr->xattr_ctx->flags &= ~BXATTR_FLAG_RESTORE_NATIVE;
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- break;
- }
- default:
- break;
- }
-
- retval = bxattr_rtn_ok;
-
-get_out:
- if (xattrbuf) {
- free(xattrbuf);
- }
- xattr_drop_internal_table(xattr_value_list);
-
- return retval;
-}
-
-/*
- * Function pointers to the build and restore function to use for these xattrs.
- */
-static bxattr_rtn_code (*os_backup_xattr_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- tru64_backup_xattr_streams;
-static bxattr_rtn_code (*os_restore_xattr_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- tru64_restore_xattr_streams;
-
-#elif defined(HAVE_SUN_OS)
-/*
- * Solaris extended attributes were introduced in Solaris 9
- * by PSARC 1999/209
- *
- * Solaris extensible attributes were introduced in OpenSolaris
- * by PSARC 2007/315 Solaris extensible attributes are also
- * sometimes called extended system attributes.
- *
- * man fsattr(5) on Solaris gives a wealth of info. The most
- * important bits are:
- *
- * Attributes are logically supported as files within the file
- * system. The file system is therefore augmented with an
- * orthogonal name space of file attributes. Any file (includ-
- * ing attribute files) can have an arbitrarily deep attribute
- * tree associated with it. Attribute values are accessed by
- * file descriptors obtained through a special attribute inter-
- * face. This logical view of "attributes as files" allows the
- * leveraging of existing file system interface functionality
- * to support the construction, deletion, and manipulation of
- * attributes.
- *
- * The special files "." and ".." retain their accustomed
- * semantics within the attribute hierarchy. The "." attribute
- * file refers to the current directory and the ".." attribute
- * file refers to the parent directory. The unnamed directory
- * at the head of each attribute tree is considered the "child"
- * of the file it is associated with and the ".." file refers
- * to the associated file. For any non-directory file with
- * attributes, the ".." entry in the unnamed directory refers
- * to a file that is not a directory.
- *
- * Conceptually, the attribute model is fully general. Extended
- * attributes can be any type of file (doors, links, direc-
- * tories, and so forth) and can even have their own attributes
- * (fully recursive). As a result, the attributes associated
- * with a file could be an arbitrarily deep directory hierarchy
- * where each attribute could have an equally complex attribute
- * tree associated with it. Not all implementations are able
- * to, or want to, support the full model. Implementation are
- * therefore permitted to reject operations that are not sup-
- * ported. For example, the implementation for the UFS file
- * system allows only regular files as attributes (for example,
- * no sub-directories) and rejects attempts to place attributes
- * on attributes.
- *
- * The following list details the operations that are rejected
- * in the current implementation:
- *
- * link Any attempt to create links between
- * attribute and non-attribute space
- * is rejected to prevent security-
- * related or otherwise sensitive
- * attributes from being exposed, and
- * therefore manipulable, as regular
- * files.
- *
- * rename Any attempt to rename between
- * attribute and non-attribute space
- * is rejected to prevent an already
- * linked file from being renamed and
- * thereby circumventing the link res-
- * triction above.
- *
- * mkdir, symlink, mknod Any attempt to create a "non-
- * regular" file in attribute space is
- * rejected to reduce the functional-
- * ity, and therefore exposure and
- * risk, of the initial implementa-
- * tion.
- *
- * The entire available name space has been allocated to "gen-
- * eral use" to bring the implementation in line with the NFSv4
- * draft standard [NFSv4]. That standard defines "named attri-
- * butes" (equivalent to Solaris Extended Attributes) with no
- * naming restrictions. All Sun applications making use of
- * opaque extended attributes will use the prefix "SUNW".
- *
- */
-#ifdef HAVE_SYS_ATTR_H
-#include <sys/attr.h>
-#endif
-
-#ifdef HAVE_ATTR_H
-#include <attr.h>
-#endif
-
-#ifdef HAVE_SYS_NVPAIR_H
-#include <sys/nvpair.h>
-#endif
-
-#ifdef HAVE_SYS_ACL_H
-#include <sys/acl.h>
-#endif
-
-#if !defined(HAVE_OPENAT) || \
- !defined(HAVE_UNLINKAT) || \
- !defined(HAVE_FCHOWNAT) || \
- !defined(HAVE_FUTIMESAT)
-#error "Unable to compile code because of missing openat, unlinkat, fchownat or futimesat function"
-#endif
-
-/*
- * Define the supported XATTR streams for this OS
- */
-#if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
-static int os_default_xattr_streams[2] = {
- STREAM_XATTR_SOLARIS,
- STREAM_XATTR_SOLARIS_SYS
-};
-#else
-static int os_default_xattr_streams[1] = {
- STREAM_XATTR_SOLARIS
-};
-#endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
-
-/*
- * This code creates a temporary cache with entries for each xattr which has
- * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
- */
-static inline xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
-{
- xattr_link_cache_entry_t *ptr;
-
- foreach_alist(ptr, jcr->xattr_ctx->link_cache) {
- if (ptr && ptr->inum == inum) {
- return ptr;
- }
- }
- return NULL;
-}
-
-static inline void add_xattr_link_cache_entry(JCR *jcr, ino_t inum, char *target)
-{
- xattr_link_cache_entry_t *ptr;
-
- ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
- memset(ptr, 0, sizeof(xattr_link_cache_entry_t));
- ptr->inum = inum;
- ptr->target = bstrdup(target);
-
- if (!jcr->xattr_ctx->link_cache) {
- jcr->xattr_ctx->link_cache = New(alist(10, not_owned_by_alist));
- }
- jcr->xattr_ctx->link_cache->append(ptr);
-}
-
-static inline void drop_xattr_link_cache(JCR *jcr)
-{
- xattr_link_cache_entry_t *ptr;
-
- /*
- * Walk the list of xattr link cache entries and free allocated memory on traversing.
- */
- foreach_alist(ptr, jcr->xattr_ctx->link_cache) {
- free(ptr->target);
- free(ptr);
- }
-
- delete jcr->xattr_ctx->link_cache;
- jcr->xattr_ctx->link_cache = NULL;
-}
-
-#if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
-/*
- * This function returns true if a non default extended system attribute
- * list is associated with fd and returns false when an error has occured
- * or when only extended system attributes other than archive,
- * av_modified or crtime are set.
- *
- * The function returns true for the following cases:
- *
- * - any extended system attribute other than the default attributes
- * ('archive', 'av_modified' and 'crtime') is set
- * - nvlist has NULL name string
- * - nvpair has data type of 'nvlist'
- * - default data type.
- */
-static bool solaris_has_non_transient_extensible_attributes(int fd)
-{
- boolean_t value;
- data_type_t type;
- nvlist_t *response;
- nvpair_t *pair;
- f_attr_t fattr;
- char *name;
- bool retval = false;
-
- if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
- return false;
- }
-
- pair = NULL;
- while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {
- name = nvpair_name(pair);
-
- if (name != NULL) {
- fattr = name_to_attr(name);
- } else {
- retval = true;
- goto get_out;
- }
-
- type = nvpair_type(pair);
- switch (type) {
- case DATA_TYPE_BOOLEAN_VALUE:
- if (nvpair_value_boolean_value(pair, &value) != 0) {
- continue;
- }
- if (value && fattr != F_ARCHIVE &&
- fattr != F_AV_MODIFIED) {
- retval = true;
- goto get_out;
- }
- break;
- case DATA_TYPE_UINT64_ARRAY:
- if (fattr != F_CRTIME) {
- retval = true;
- goto get_out;
- }
- break;
- case DATA_TYPE_NVLIST:
- default:
- retval = true;
- goto get_out;
- }
- }
-
-get_out:
- if (response != NULL) {
- nvlist_free(response);
- }
- return retval;
-}
-#endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
-
-#if defined(HAVE_ACL) && !defined(HAVE_EXTENDED_ACL)
-/*
- * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
- * There is no need to store those acls as we already store the stat bits too.
- */
-static bool acl_is_trivial(int count, aclent_t *entries)
-{
- int n;
- aclent_t *ace;
-
- for (n = 0; n < count; n++) {
- ace = &entries[n];
- if (!(ace->a_type == USER_OBJ ||
- ace->a_type == GROUP_OBJ ||
- ace->a_type == OTHER_OBJ ||
- ace->a_type == CLASS_OBJ))
- return false;
- }
- return true;
-}
-#endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
-
-static bxattr_rtn_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
-{
- bxattr_rtn_code retval = bxattr_rtn_error;
-#ifdef HAVE_ACL
-#ifdef HAVE_EXTENDED_ACL
- int flags;
- acl_t *aclp = NULL;
-
- /*
- * See if this attribute has an ACL
- */
- if ((fd != -1 && fpathconf(fd, _PC_ACL_ENABLED) > 0) ||
- pathconf(attrname, _PC_ACL_ENABLED) > 0) {
- /*
- * See if there is a non trivial acl on the file.
- */
- if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
- acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
- attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
- if (aclp != NULL) {
-#if defined(ACL_SID_FMT)
- /*
- * New format flag added in newer Solaris versions.
- */
- flags = ACL_APPEND_ID | ACL_COMPACT_FMT | ACL_SID_FMT;
-#else
- flags = ACL_APPEND_ID | ACL_COMPACT_FMT;
-#endif /* ACL_SID_FMT */
-
- *acl_text = acl_totext(aclp, flags);
- acl_free(aclp);
- } else {
- *acl_text = NULL;
- }
- } else {
- *acl_text = NULL;
- }
- retval = bxattr_rtn_ok;
-#else /* HAVE_EXTENDED_ACL */
- int n;
- aclent_t *acls = NULL;
-
- /*
- * See if this attribute has an ACL
- */
- if (fd != -1) {
- n = facl(fd, GETACLCNT, 0, NULL);
- } else {
- n = acl(attrname, GETACLCNT, 0, NULL);
- }
-
- if (n >= MIN_ACL_ENTRIES) {
- acls = (aclent_t *)malloc(n * sizeof(aclent_t));
- if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
- acl(attrname, GETACL, n, acls) != n) {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- free(acls);
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
- attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- free(acls);
- goto get_out;
- }
- }
-
- /*
- * See if there is a non trivial acl on the file.
- */
- if (!acl_is_trivial(n, acls)) {
- if ((*acl_text = acltotext(acls, n)) == NULL) {
- berrno be;
-
- Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
- attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- free(acls);
- goto get_out;
- }
- } else {
- *acl_text = NULL;
- }
-
- free(acls);
- } else {
- *acl_text = NULL;
- }
- retval = bxattr_rtn_ok;
-#endif /* HAVE_EXTENDED_ACL */
-
-#else /* HAVE_ACL */
- retval = bxattr_rtn_ok;
-#endif /* HAVE_ACL */
-
-get_out:
- return retval;
-}
-
-/*
- * Forward declaration for recursive function call.
- */
-static bxattr_rtn_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
-
-/*
- * Save an extended or extensible attribute.
- * This is stored as an opaque stream of bytes with the following encoding:
- *
- * <xattr_name>\0<stat_buffer>\0<acl_string>\0<actual_xattr_ctx>
- *
- * or for a hardlinked or symlinked attribute
- *
- * <xattr_name>\0<stat_buffer>\0<xattr_link_source>\0
- *
- * xattr_name can be a subpath relative to the file the xattr is on.
- * stat_buffer is the string representation of the stat struct.
- * acl_string is an acl text when a non trivial acl is set on the xattr.
- * actual_xattr_ctx is the content of the xattr file.
- */
-static bxattr_rtn_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
- const char *attrname, bool toplevel_hidden_dir, int stream)
-{
- int cnt;
- int attrfd = -1;
- struct stat st;
- xattr_link_cache_entry_t *xlce;
- char target_attrname[PATH_MAX];
- char link_source[PATH_MAX];
- char *acl_text = NULL;
- char attribs[MAXSTRING];
- char buffer[XATTR_BUFSIZ];
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
-
- /*
- * Get the stats of the extended or extensible attribute.
- */
- if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
- /*
- * Based on the filetype perform the correct action. We support most filetypes here, more
- * then the actual implementation on Solaris supports so some code may never get executed
- * due to limitations in the implementation.
- */
- switch (st.st_mode & S_IFMT) {
- case S_IFIFO:
- case S_IFCHR:
- case S_IFBLK:
- /*
- * Get any acl on the xattr.
- */
- if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_rtn_ok)
- goto get_out;
-
- /*
- * The current implementation of xattr on Solaris doesn't support this,
- * but if it ever does we are prepared.
- * Encode the stat struct into an ASCII representation.
- */
- encode_stat(attribs, &st, sizeof(st), 0, stream);
- cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
- target_attrname, 0, attribs, 0,
- (acl_text) ? acl_text : "", 0);
- break;
- case S_IFDIR:
- /*
- * Get any acl on the xattr.
- */
- if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_rtn_ok)
- goto get_out;
-
- /*
- * See if this is the toplevel_hidden_dir being saved.
- */
- if (toplevel_hidden_dir) {
- /*
- * Save the data for later storage when we encounter a real xattr.
- * We store the data in the jcr->xattr_ctx->content buffer
- * and flush that just before sending out the first real xattr.
- * Encode the stat struct into an ASCII representation and jump
- * out of the function.
- */
- encode_stat(attribs, &st, sizeof(st), 0, stream);
- cnt = bsnprintf(buffer, sizeof(buffer),
- "%s%c%s%c%s%c",
- target_attrname, 0, attribs, 0,
- (acl_text) ? acl_text : "", 0);
- pm_memcpy(jcr->xattr_ctx->content, buffer, cnt);
- jcr->xattr_ctx->content_length = cnt;
- goto get_out;
- } else {
- /*
- * The current implementation of xattr on Solaris doesn't support this,
- * but if it ever does we are prepared.
- * Encode the stat struct into an ASCII representation.
- */
- encode_stat(attribs, &st, sizeof(st), 0, stream);
- cnt = bsnprintf(buffer, sizeof(buffer),
- "%s%c%s%c%s%c",
- target_attrname, 0, attribs, 0,
- (acl_text) ? acl_text : "", 0);
- }
- break;
- case S_IFREG:
- /*
- * If this is a hardlinked file check the inode cache for a hit.
- */
- if (st.st_nlink > 1) {
- /*
- * See if the cache already knows this inode number.
- */
- if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
- /*
- * Generate a xattr encoding with the reference to the target in there.
- */
- encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
- cnt = bsnprintf(buffer, sizeof(buffer),
- "%s%c%s%c%s%c",
- target_attrname, 0, attribs, 0, xlce->target, 0);
- pm_memcpy(jcr->xattr_ctx->content, buffer, cnt);
- jcr->xattr_ctx->content_length = cnt;
- retval = send_xattr_stream(jcr, stream);
-
- /*
- * For a hard linked file we are ready now, no need to recursively
- * save the attributes.
- */
- goto get_out;
- }
-
- /*
- * Store this hard linked file in the cache.
- * Store the name relative to the top level xattr space.
- */
- add_xattr_link_cache_entry(jcr, st.st_ino, target_attrname + 1);
- }
-
- /*
- * Get any acl on the xattr.
- */
- if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_rtn_ok) {
- goto get_out;
- }
-
- /*
- * Encode the stat struct into an ASCII representation.
- */
- encode_stat(attribs, &st, sizeof(st), 0, stream);
- cnt = bsnprintf(buffer, sizeof(buffer),
- "%s%c%s%c%s%c",
- target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
-
- /*
- * Open the extended or extensible attribute file.
- */
- if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
- break;
- case S_IFLNK:
- /*
- * The current implementation of xattr on Solaris doesn't support this, but if it
- * ever does we are prepared.
- * Encode the stat struct into an ASCII representation.
- */
- if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
- /*
- * Generate a xattr encoding with the reference to the target in there.
- */
- encode_stat(attribs, &st, sizeof(st), st.st_ino, stream);
- cnt = bsnprintf(buffer, sizeof(buffer),
- "%s%c%s%c%s%c",
- target_attrname, 0, attribs, 0, link_source, 0);
- pm_memcpy(jcr->xattr_ctx->content, buffer, cnt);
- jcr->xattr_ctx->content_length = cnt;
- retval = send_xattr_stream(jcr, stream);
-
- if (retval == bxattr_rtn_ok) {
- jcr->xattr_ctx->nr_saved++;
- }
-
- /*
- * For a soft linked file we are ready now, no need to recursively save the attributes.
- */
- goto get_out;
- default:
- goto get_out;
- }
-
- /*
- * See if this is the first real xattr being saved.
- * If it is save the toplevel_hidden_dir attributes first.
- * This is easy as its stored already in the
- * jcr->xattr_ctx->content buffer.
- */
- if (jcr->xattr_ctx->nr_saved == 0) {
- retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
- if (retval != bxattr_rtn_ok) {
- goto get_out;
- }
- jcr->xattr_ctx->nr_saved++;
- }
-
- pm_memcpy(jcr->xattr_ctx->content, buffer, cnt);
- jcr->xattr_ctx->content_length = cnt;
-
- /*
- * Only dump the content of regular files.
- */
- switch (st.st_mode & S_IFMT) {
- case S_IFREG:
- if (st.st_size > 0) {
- /*
- * Protect ourself against things getting out of hand.
- */
- if (st.st_size >= MAX_XATTR_LENGTH) {
- Mmsg2(jcr->errmsg,
- _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
- jcr->last_fname, MAX_XATTR_LENGTH);
- goto get_out;
- }
-
- while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
- jcr->xattr_ctx->content =
- check_pool_memory_size(jcr->xattr_ctx->content,
- jcr->xattr_ctx->content_length + cnt);
- memcpy(jcr->xattr_ctx->content +
- jcr->xattr_ctx->content_length, buffer, cnt);
- jcr->xattr_ctx->content_length += cnt;
- }
-
- if (cnt < 0) {
- Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
- target_attrname, jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
- break;
-
- default:
- break;
- }
-
- /*
- * We build a new xattr stream send it to the SD.
- */
- retval = send_xattr_stream(jcr, stream);
- if (retval != bxattr_rtn_ok) {
- goto get_out;
- }
- jcr->xattr_ctx->nr_saved++;
-
- /*
- * Recursivly call solaris_save_extended_attributes for archiving the attributes
- * available on this extended attribute.
- */
- retval = solaris_save_xattrs(jcr, xattr_namespace, attrname);
-
- /*
- * The recursive call could change our working dir so change back to the wanted workdir.
- */
- if (fchdir(fd) < 0) {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
-get_out:
- if (acl_text != NULL) {
- free(acl_text);
- }
- if (attrfd != -1) {
- close(attrfd);
- }
- return retval;
-}
-
-static bxattr_rtn_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
-{
- const char *name;
- int fd, filefd = -1, attrdirfd = -1;
- DIR *dirp;
- struct dirent *dp;
- char current_xattr_namespace[PATH_MAX];
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- /*
- * Determine what argument to use. Use attr_parent when set
- * (recursive call) or jcr->last_fname for first call. Also save
- * the current depth of the xattr_space we are in.
- */
- if (attr_parent) {
- name = attr_parent;
- if (xattr_namespace) {
- bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
- xattr_namespace, attr_parent);
- } else {
- bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
- }
- } else {
- name = jcr->last_fname;
- bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
- }
-
- /*
- * Open the file on which to save the xattrs read-only.
- */
- if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
- berrno be;
-
- switch (errno) {
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
- /*
- * Open the xattr naming space.
- */
- if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
- berrno be;
-
- switch (errno) {
- case EINVAL:
- /*
- * Gentile way of the system saying this type of xattr layering is not supported.
- * Which is not problem we just forget about this this xattr.
- * But as this is not an error we return a positive return value.
- */
- retval = bxattr_rtn_ok;
- goto get_out;
- case ENOENT:
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
- name, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
- /*
- * We need to change into the attribute directory to determine if each of the
- * attributes should be saved.
- */
- if (fchdir(attrdirfd) < 0) {
- berrno be;
-
- Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Save the data of the toplevel xattr hidden_dir. We save this one before anything
- * else because the readdir returns "." entry after the extensible attr entry.
- * And as we want this entry before anything else we better just save its data.
- */
- if (!attr_parent)
- solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
- true, STREAM_XATTR_SOLARIS);
-
- if ((fd = dup(attrdirfd)) == -1 ||
- (dirp = fdopendir(fd)) == (DIR *)NULL) {
- berrno be;
-
- Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
-
- goto get_out;
- }
-
- /*
- * Walk the namespace.
- */
- while ((dp = readdir(dirp)) != NULL) {
- /*
- * Skip only the toplevel . dir.
- */
- if (!attr_parent && bstrcmp(dp->d_name, "."))
- continue;
-
- /*
- * Skip all .. directories
- */
- if (bstrcmp(dp->d_name, ".."))
- continue;
-
- Dmsg3(400, "processing extended attribute %s%s on file \"%s\"\n",
- current_xattr_namespace, dp->d_name, jcr->last_fname);
-
-#if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
- /*
- * We are not interested in read-only extensible attributes.
- */
- if (bstrcmp(dp->d_name, VIEW_READONLY)) {
- Dmsg3(400, "Skipping readonly extensible attributes %s%s on file \"%s\"\n",
- current_xattr_namespace, dp->d_name, jcr->last_fname);
-
- continue;
- }
-
- /*
- * We are only interested in read-write extensible attributes
- * when they contain non-transient values.
- */
- if (bstrcmp(dp->d_name, VIEW_READWRITE)) {
- /*
- * Determine if there are non-transient system attributes at the toplevel.
- * We need to provide a fd to the open file.
- */
- if (!solaris_has_non_transient_extensible_attributes(filefd)) {
- Dmsg3(400, "Skipping transient extensible attributes %s%s on file \"%s\"\n",
- current_xattr_namespace, dp->d_name, jcr->last_fname);
- continue;
- }
-
- /*
- * Save the xattr.
- */
- solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
- false, STREAM_XATTR_SOLARIS_SYS);
- continue;
- }
-#endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
-
- /*
- * Save the xattr.
- */
- solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
- false, STREAM_XATTR_SOLARIS);
- }
-
- closedir(dirp);
- retval = bxattr_rtn_ok;
-
-get_out:
- if (attrdirfd != -1)
- close(attrdirfd);
- if (filefd != -1)
- close(filefd);
- return retval;
-}
-
-#ifdef HAVE_ACL
-static bxattr_rtn_code solaris_restore_xattr_acl(JCR *jcr,
- int fd,
- const char *attrname,
- char *acl_text)
-{
-#ifdef HAVE_EXTENDED_ACL
- int error;
- acl_t *aclp = NULL;
-
- if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
- Mmsg1(jcr->errmsg,
- _("Unable to convert acl from text on file \"%s\"\n"),
- jcr->last_fname);
- return bxattr_rtn_error;
- }
-
- if ((fd != -1 && facl_set(fd, aclp) != 0) ||
- acl_set(attrname, aclp) != 0) {
- berrno be;
-
- Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
- attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bxattr_rtn_error;
- }
-
- if (aclp) {
- acl_free(aclp);
- }
- return bxattr_rtn_ok;
-
-#else /* HAVE_EXTENDED_ACL */
- int n;
- aclent_t *acls = NULL;
-
- acls = aclfromtext(acl_text, &n);
- if (!acls) {
- if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
- acl(attrname, SETACL, n, acls) != 0) {
- berrno be;
-
- Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
- attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- return bxattr_rtn_error;
- }
- }
-
- if (acls) {
- free(acls);
- }
- return bxattr_rtn_ok;
-
-#endif /* HAVE_EXTENDED_ACL */
-
-}
-#endif /* HAVE_ACL */
-
-static bxattr_rtn_code solaris_restore_xattrs(JCR *jcr,
- bool is_extensible,
- char *content,
- uint32_t content_length)
-
-{
- int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
- int used_bytes, cnt;
- char *bp, *target_attrname, *attribs;
- char *linked_target = NULL;
- char *acl_text = NULL;
- char *data = NULL;
- int32_t inum;
- struct stat st;
- struct timeval times[2];
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- /*
- * Restore the xattr stream. First the part that is the same for all xattrs.
- */
- used_bytes = 0;
-
- /*
- * The name of the target xattr has a leading / we are not interested
- * in that so skip it when decoding the string. We always start a the /
- * of the xattr space anyway.
- */
- target_attrname = content + 1;
- if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
- (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
- goto restore_error;
- }
- attribs = ++bp;
-
- /*
- * Open the file on which to restore the xattrs read-only.
- */
- if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
- berrno be;
-
- Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Open the xattr naming space and make it the current working dir.
- */
- if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
- berrno be;
-
- Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- if (fchdir(attrdirfd) < 0) {
- berrno be;
-
- Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Try to open the correct xattr subdir based on the target_attrname given.
- * e.g. check if its a subdir attrname. Each / in the string makes us go
- * one level deeper.
- */
- while ((bp = strchr(target_attrname, '/')) != (char *)NULL) {
- *bp = '\0';
-
- if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
- berrno be;
-
- Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- close(filefd);
- filefd = fd;
-
- /*
- * Open the xattr naming space.
- */
- if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
- berrno be;
-
- Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- close(attrdirfd);
- attrdirfd = fd;
-
- /*
- * Make the xattr space our current workingdir.
- */
- if (fchdir(attrdirfd) < 0) {
- berrno be;
-
- Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- target_attrname = ++bp;
- }
-
- /*
- * Decode the attributes from the stream.
- */
- decode_stat(attribs, &st, sizeof(st), &inum);
-
- /*
- * Decode the next field (acl_text).
- */
- if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
- (used_bytes = (bp - content)) >= (int32_t)(content_length - 1)) {
- goto restore_error;
- }
- acl_text = ++bp;
-
- /*
- * Based on the filetype perform the correct action. We support most filetypes here, more
- * then the actual implementation on Solaris supports so some code may never get executed
- * due to limitations in the implementation.
- */
- switch (st.st_mode & S_IFMT) {
- case S_IFIFO:
- /*
- * The current implementation of xattr on Solaris doesn't support this,
- * but if it ever does we are prepared.
- */
- unlinkat(attrdirfd, target_attrname, 0);
- if (mkfifo(target_attrname, st.st_mode) < 0) {
- berrno be;
-
- Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- break;
- case S_IFCHR:
- case S_IFBLK:
- /*
- * The current implementation of xattr on Solaris doesn't support this,
- * but if it ever does we are prepared.
- */
- unlinkat(attrdirfd, target_attrname, 0);
- if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
- berrno be;
-
- Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- break;
- case S_IFDIR:
- /*
- * If its not the hidden_dir create the entry.
- * The current implementation of xattr on Solaris doesn't support this,
- * but if it ever does we are prepared.
- */
- if (!bstrcmp(target_attrname, ".")) {
- unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
- if (mkdir(target_attrname, st.st_mode) < 0) {
- berrno be;
-
- /* *** FIXME *** why not Mmsg? */
- Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
- target_attrname, jcr->last_fname, be.bstrerror());
- goto get_out;
- }
- }
- break;
- case S_IFREG:
- /*
- * See if this is a hard linked file. e.g. inum != 0
- */
- if (inum != 0) {
- linked_target = bp;
-
- unlinkat(attrdirfd, target_attrname, 0);
- if (link(linked_target, target_attrname) < 0) {
- berrno be;
-
- Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
- target_attrname, linked_target, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Successfully restored xattr.
- */
- retval = bxattr_rtn_ok;
- goto get_out;
- } else {
- if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
- (used_bytes = (bp - content)) >= (int32_t)content_length) {
- goto restore_error;
- }
-
- if (used_bytes < (int32_t)(content_length - 1))
- data = ++bp;
-
- /*
- * Restore the actual xattr.
- */
- if (!is_extensible) {
- unlinkat(attrdirfd, target_attrname, 0);
- }
-
- if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
- berrno be;
-
- Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
- /*
- * Restore the actual data.
- */
- if (st.st_size > 0) {
- used_bytes = (data - content);
- cnt = content_length - used_bytes;
-
- /*
- * Do a sanity check, the st.st_size should be the same as the number of bytes
- * we have available as data of the stream.
- */
- if (cnt != st.st_size) {
- Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
- target_attrname, jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- while (cnt > 0) {
- cnt = write(attrfd, data, cnt);
- if (cnt < 0) {
- berrno be;
-
- Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- used_bytes += cnt;
- data += cnt;
- cnt = content_length - used_bytes;
- }
- }
- break;
- case S_IFLNK:
- /*
- * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
- */
- linked_target = bp;
-
- if (symlink(linked_target, target_attrname) < 0) {
- berrno be;
-
- Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
- target_attrname, linked_target, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- /*
- * Successfully restored xattr.
- */
- retval = bxattr_rtn_ok;
- goto get_out;
- default:
- goto get_out;
- }
-
- /*
- * Restore owner and acl for non extensible attributes.
- */
- if (!is_extensible) {
- if (fchownat(attrdirfd, target_attrname, st.st_uid, st.st_gid, AT_SYMLINK_NOFOLLOW) < 0) {
- berrno be;
- /* EINVAL means is not supported, no fail */
- if (errno == EINVAL || errno == ENOENT) {
- retval = bxattr_rtn_ok;
- } else {
- Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- }
- goto get_out;
- }
- }
-
-#ifdef HAVE_ACL
- if (acl_text && *acl_text)
- if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_rtn_ok)
- goto get_out;
-#endif /* HAVE_ACL */
-
- /*
- * For a non extensible attribute restore access and modification time on the xattr.
- */
- if (!is_extensible) {
- times[0].tv_sec = st.st_atime;
- times[0].tv_usec = 0;
- times[1].tv_sec = st.st_mtime;
- times[1].tv_usec = 0;
-
- if (futimesat(attrdirfd, target_attrname, times) < 0) {
- berrno be;
- Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
- target_attrname, jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- }
-
- /*
- * Successfully restored xattr.
- */
- retval = bxattr_rtn_ok;
- goto get_out;
-
-restore_error:
- Mmsg1(jcr->errmsg, _("Invalid xattr stream, failed to restore xattr stream on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
-
-get_out:
- if (attrfd != -1) {
- close(attrfd);
- }
- if (attrdirfd != -1) {
- close(attrdirfd);
- }
- if (filefd != -1) {
- close(filefd);
- }
- return retval;
-}
-
-static bxattr_rtn_code solaris_backup_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- char cwd[PATH_MAX];
- bxattr_rtn_code retval = bxattr_rtn_ok;
-
- /*
- * First see if extended attributes or extensible attributes are present.
- * If not just pretend things went ok.
- */
- if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
- jcr->xattr_ctx->nr_saved = 0;
-
- /*
- * As we change the cwd in the save function save the current cwd
- * for restore after return from the solaris_save_xattrs function.
- */
- getcwd(cwd, sizeof(cwd));
- retval = solaris_save_xattrs(jcr, NULL, NULL);
- chdir(cwd);
- if (jcr->xattr_ctx->link_cache) {
- drop_xattr_link_cache(jcr);
- }
- }
- return retval;
-}
-
-static bxattr_rtn_code solaris_restore_xattr_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
- char cwd[PATH_MAX];
- bool is_extensible = false;
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- /*
- * First make sure we can restore xattr on the filesystem.
- */
- switch (stream) {
-#if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
- case STREAM_XATTR_SOLARIS_SYS:
- if (pathconf(jcr->last_fname, _PC_SATTR_ENABLED) <= 0) {
- Mmsg1(jcr->errmsg, _("Failed to restore extensible attributes on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
-
- is_extensible = true;
- break;
-#endif
- case STREAM_XATTR_SOLARIS:
- if (pathconf(jcr->last_fname, _PC_XATTR_ENABLED) <= 0) {
- Mmsg1(jcr->errmsg, _("Failed to restore extended attributes on file \"%s\"\n"),
- jcr->last_fname);
- Dmsg1(100, "%s", jcr->errmsg);
- goto get_out;
- }
- break;
- default:
- goto get_out;
- }
-
- /*
- * As we change the cwd in the restore function save the current cwd
- * for restore after return from the solaris_restore_xattrs function.
- */
- getcwd(cwd, sizeof(cwd));
- retval = solaris_restore_xattrs(jcr, is_extensible, content, content_length);
- chdir(cwd);
-
-get_out:
- return retval;
-}
-
-
-/*
- * Function pointers to the build and restore function to use for these xattrs.
- */
-static bxattr_rtn_code (*os_backup_xattr_streams)
- (JCR *jcr, FF_PKT *ff_pkt) =
- solaris_backup_xattr_streams;
-static bxattr_rtn_code (*os_restore_xattr_streams)
- (JCR *jcr, int stream, char *content, uint32_t content_length) =
- solaris_restore_xattr_streams;
-
-#endif /* defined(HAVE_SUN_OS) */
-
-/*
- * Entry points when compiled with support for XATTRs on a supported platform.
- */
-bool backup_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
- bxattr_rtn_code rtn = bxattr_rtn_ok;
-
- if (!(ff_pkt->flags & FO_XATTR && !ff_pkt->cmd_plugin)) {
- return true;
- }
-
- jcr->errmsg[0] = 0;
-
- /*
- * See if we are changing from one device to an other.
- * We save the current device we are scanning and compare
- * it with the current st_dev in the last stat performed on
- * the file we are currently storing.
- */
- if (jcr->xattr_ctx->current_dev != ff_pkt->statp.st_dev) {
- /*
- * Reset the acl save flags.
- */
- jcr->xattr_ctx->flags = 0;
- jcr->xattr_ctx->flags |= BXATTR_FLAG_SAVE_NATIVE;
-
- /*
- * Save that we started scanning a new filesystem.
- */
- jcr->xattr_ctx->current_dev = ff_pkt->statp.st_dev;
- }
-
- if ((jcr->xattr_ctx->flags & BXATTR_FLAG_SAVE_NATIVE) && os_restore_xattr_streams) {
- rtn = os_backup_xattr_streams(jcr, ff_pkt);
- }
- switch (rtn) {
- case bxattr_rtn_fatal:
- return false;
- case bxattr_rtn_ok:
- return true;
- case bxattr_rtn_error:
- if (jcr->xattr_ctx->nr_errors < XATTR_MAX_ERROR_PRINT_PER_JOB) {
- if (jcr->errmsg[0]) {
- Jmsg(jcr, M_WARNING, 0, "Operating system XATTRs not configured.\n");
- } else {
- Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
- }
- jcr->xattr_ctx->nr_errors++;
- }
- return true;
- }
- /* Theoretically we cannot get here */
- return false;
-
-}
-
-bxattr_rtn_code restore_xattr_streams(JCR *jcr,
- int stream,
- char *content,
- uint32_t content_length)
-{
- int ret;
- struct stat st;
- unsigned int cnt;
- bxattr_rtn_code retval = bxattr_rtn_error;
-
- /*
- * See if we are changing from one device to an other.
- * We save the current device we are restoring to and compare
- * it with the current st_dev in the last stat performed on
- * the file we are currently restoring.
- */
- ret = lstat(jcr->last_fname, &st);
- if (ret < 0) {
- berrno be;
- if (errno == ENOENT) {
- retval = bxattr_rtn_ok;
- } else {
- Mmsg2(jcr->errmsg, _("Unable to stat file \"%s\": ERR=%s\n"),
- jcr->last_fname, be.bstrerror());
- Dmsg1(100, "%s", jcr->errmsg);
- }
- goto get_out;
- }
- if (jcr->xattr_ctx->current_dev != st.st_dev) {
- /*
- * Reset the acl save flags.
- */
- jcr->xattr_ctx->flags = 0;
- jcr->xattr_ctx->flags |= BXATTR_FLAG_RESTORE_NATIVE;
-
- /*
- * Save that we started restoring to a new filesystem.
- */
- jcr->xattr_ctx->current_dev = st.st_dev;
- }
-
- /*
- * See if we are still restoring native xattr to this filesystem.
- */
- if ((jcr->xattr_ctx->flags & BXATTR_FLAG_RESTORE_NATIVE) && os_restore_xattr_streams) {
- /*
- * See if we can restore this stream, and ifso give it a try.
- */
- for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
- if (os_default_xattr_streams[cnt] == stream) {
- retval = os_restore_xattr_streams(jcr, stream, content, content_length);
- goto get_out;
- }
- }
- } else {
- /*
- * Increment error count but don't log an error again for the same filesystem.
- */
- jcr->xattr_ctx->nr_errors++;
- retval = bxattr_rtn_ok;
- goto get_out;
- }
-
- /*
- * Issue a warning and discard the message. But pretend the restore was ok.
- */
- Jmsg2(jcr, M_WARNING, 0,
- _("Cannot restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
- jcr->last_fname, stream);
-
-get_out:
- return retval;
-}
-#endif
+++ /dev/null
-/*
- Bacula(R) - The Network Backup Solution
-
- Copyright (C) 2000-2015 Kern Sibbald
- Copyright (C) 2004-2014 Free Software Foundation Europe e.V.
-
- The original author of Bacula is Kern Sibbald, with contributions
- from many others, a complete list can be found in the file AUTHORS.
-
- You may use this file and others of this release according to the
- license defined in the LICENSE file, which includes the Affero General
- Public License, v3.0 ("AGPLv3") and some additional permissions and
- terms pursuant to its AGPLv3 Section 7.
-
- This notice must be preserved when any source code is
- conveyed and/or propagated.
-
- Bacula(R) is a registered trademark of Kern Sibbald.
-*/
-
-#ifndef BACULA_XATTR_H_
-#define BACULA_XATTR_H_
-
-#if defined(HAVE_LINUX_OS)
-#define BXATTR_ENOTSUP EOPNOTSUPP
-#elif defined(HAVE_DARWIN_OS)
-#define BXATTR_ENOTSUP ENOTSUP
-#elif defined(HAVE_HURD_OS)
-#define BXATTR_ENOTSUP ENOTSUP
-#endif
-
-/*
- * 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.
- */
-struct xattr_t {
- uint32_t magic;
- uint32_t name_length;
- char *name;
- uint32_t value_length;
- char *value;
-};
-
-/*
- * Internal representation of an extended attribute hardlinked file.
- */
-struct xattr_link_cache_entry_t {
- uint32_t inum;
- char *target;
-};
-
-#define BXATTR_FLAG_SAVE_NATIVE 0x01
-#define BXATTR_FLAG_RESTORE_NATIVE 0x02
-
-/*
- * Internal tracking data.
- */
-struct xattr_ctx_t {
- uint32_t flags; /* See BXATTR_FLAG_* */
- uint32_t current_dev;
- uint32_t nr_errors;
- uint32_t nr_saved;
- POOLMEM *content;
- uint32_t content_length;
- alist *link_cache;
-};
-
-#define MAX_XATTR_LENGTH (1 * 1024 * 1024) /* 1 Mb */
-
-#define XATTR_BUFSIZ 1024
-
-#endif /* BACULA_XATTR_H_ */
return _("Plugin Data");
case STREAM_RESTORE_OBJECT:
return _("Restore Object");
- case STREAM_ACL_AIX_TEXT:
+ case STREAM_XACL_AIX_TEXT:
return _("AIX ACL attribs");
- case STREAM_ACL_DARWIN_ACCESS:
+ case STREAM_XACL_DARWIN_ACCESS:
return _("Darwin ACL attribs");
- case STREAM_ACL_FREEBSD_DEFAULT:
+ case STREAM_XACL_FREEBSD_DEFAULT:
return _("FreeBSD Default ACL attribs");
- case STREAM_ACL_FREEBSD_ACCESS:
+ case STREAM_XACL_FREEBSD_ACCESS:
return _("FreeBSD Access ACL attribs");
- case STREAM_ACL_HPUX_ACL_ENTRY:
+ case STREAM_XACL_HPUX_ACL_ENTRY:
return _("HPUX ACL attribs");
- case STREAM_ACL_IRIX_DEFAULT:
+ case STREAM_XACL_IRIX_DEFAULT:
return _("Irix Default ACL attribs");
- case STREAM_ACL_IRIX_ACCESS:
+ case STREAM_XACL_IRIX_ACCESS:
return _("Irix Access ACL attribs");
- case STREAM_ACL_LINUX_DEFAULT:
+ case STREAM_XACL_LINUX_DEFAULT:
return _("Linux Default ACL attribs");
- case STREAM_ACL_LINUX_ACCESS:
+ case STREAM_XACL_LINUX_ACCESS:
return _("Linux Access ACL attribs");
- case STREAM_ACL_TRU64_DEFAULT:
+ case STREAM_XACL_TRU64_DEFAULT:
return _("TRU64 Default ACL attribs");
- case STREAM_ACL_TRU64_ACCESS:
+ case STREAM_XACL_TRU64_ACCESS:
return _("TRU64 Access ACL attribs");
- case STREAM_ACL_SOLARIS_POSIX:
+ case STREAM_XACL_SOLARIS_POSIX:
return _("Solaris POSIX ACL attribs");
- case STREAM_ACL_SOLARIS_NFS4:
+ case STREAM_XACL_SOLARIS_NFS4:
return _("Solaris NFSv4/ZFS ACL attribs");
- case STREAM_ACL_AFS_TEXT:
+ case STREAM_XACL_AFS_TEXT:
return _("AFS ACL attribs");
- case STREAM_ACL_AIX_AIXC:
+ case STREAM_XACL_AIX_AIXC:
return _("AIX POSIX ACL attribs");
- case STREAM_ACL_AIX_NFS4:
+ case STREAM_XACL_AIX_NFS4:
return _("AIX NFSv4 ACL attribs");
- case STREAM_ACL_FREEBSD_NFS4:
+ case STREAM_XACL_FREEBSD_NFS4:
return _("FreeBSD NFSv4/ZFS ACL attribs");
- case STREAM_ACL_HURD_DEFAULT:
+ case STREAM_XACL_HURD_DEFAULT:
return _("GNU Hurd Default ACL attribs");
- case STREAM_ACL_HURD_ACCESS:
+ case STREAM_XACL_HURD_ACCESS:
return _("GNU Hurd Access ACL attribs");
- case STREAM_XATTR_HURD:
+ case STREAM_XACL_HURD_XATTR:
return _("GNU Hurd Extended attribs");
- case STREAM_XATTR_IRIX:
+ case STREAM_XACL_IRIX_XATTR:
return _("IRIX Extended attribs");
- case STREAM_XATTR_TRU64:
+ case STREAM_XACL_TRU64_XATTR:
return _("TRU64 Extended attribs");
- case STREAM_XATTR_AIX:
+ case STREAM_XACL_AIX_XATTR:
return _("AIX Extended attribs");
- case STREAM_XATTR_OPENBSD:
+ case STREAM_XACL_OPENBSD_XATTR:
return _("OpenBSD Extended attribs");
- case STREAM_XATTR_SOLARIS_SYS:
+ case STREAM_XACL_SOLARIS_SYS_XATTR:
return _("Solaris Extensible attribs or System Extended attribs");
- case STREAM_XATTR_SOLARIS:
+ case STREAM_XACL_SOLARIS_XATTR:
return _("Solaris Extended attribs");
- case STREAM_XATTR_DARWIN:
+ case STREAM_XACL_DARWIN_XATTR:
return _("Darwin Extended attribs");
- case STREAM_XATTR_FREEBSD:
+ case STREAM_XACL_FREEBSD_XATTR:
return _("FreeBSD Extended attribs");
- case STREAM_XATTR_LINUX:
+ case STREAM_XACL_LINUX_XATTR:
return _("Linux Extended attribs");
- case STREAM_XATTR_NETBSD:
+ case STREAM_XACL_NETBSD_XATTR:
return _("NetBSD Extended attribs");
default:
sprintf(buf, "%d", stream);
/*
Bacula(R) - The Network Backup Solution
- Copyright (C) 2000-2015 Kern Sibbald
- Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2016 Kern Sibbald
The original author of Bacula is Kern Sibbald, with contributions
from many others, a complete list can be found in the file AUTHORS.
Public License, v3.0 ("AGPLv3") and some additional permissions and
terms pursuant to its AGPLv3 Section 7.
- This notice must be preserved when any source code is
+ This notice must be preserved when any source code is
conveyed and/or propagated.
Bacula(R) is a registered trademark of Kern Sibbald.
#ifdef FILE_DAEMON
class htable;
-struct acl_ctx_t;
-struct xattr_ctx_t;
+class XACL;
class snapshot_manager;
struct CRYPTO_CTX {
POOLMEM *last_fname; /* last file saved/verified */
POOLMEM *job_metadata; /* VSS job metadata */
pthread_cond_t job_start_wait; /* Wait for SD to start Job */
- acl_ctx_t *acl_ctx; /* ACLs for backup/restore */
- xattr_ctx_t *xattr_ctx; /* Extended Attributes for backup/restore */
+ XACL *xacl; /* ACLs and Extended Attributes for backup/restore */
int32_t last_type; /* type of last file saved/verified */
int incremental; /* set if incremental for SINCE */
time_t last_stat_time; /* Last time stats sent to Dir */
case STREAM_UNIX_ACCESS_ACL: /* Deprecated Standard ACL attributes on UNIX */
case STREAM_UNIX_DEFAULT_ACL: /* Deprecated Default ACL attributes on UNIX */
case STREAM_HFSPLUS_ATTRIBUTES:
- case STREAM_ACL_AIX_TEXT:
- case STREAM_ACL_DARWIN_ACCESS:
- case STREAM_ACL_FREEBSD_DEFAULT:
- case STREAM_ACL_FREEBSD_ACCESS:
- case STREAM_ACL_HPUX_ACL_ENTRY:
- case STREAM_ACL_IRIX_DEFAULT:
- case STREAM_ACL_IRIX_ACCESS:
- case STREAM_ACL_LINUX_DEFAULT:
- case STREAM_ACL_LINUX_ACCESS:
- case STREAM_ACL_TRU64_DEFAULT:
- case STREAM_ACL_TRU64_DEFAULT_DIR:
- case STREAM_ACL_TRU64_ACCESS:
- case STREAM_ACL_SOLARIS_POSIX:
- case STREAM_ACL_SOLARIS_NFS4:
- case STREAM_ACL_AFS_TEXT:
- case STREAM_ACL_AIX_AIXC:
- case STREAM_ACL_AIX_NFS4:
- case STREAM_ACL_FREEBSD_NFS4:
- case STREAM_ACL_HURD_DEFAULT:
- case STREAM_ACL_HURD_ACCESS:
+ case STREAM_XACL_AIX_TEXT:
+ case STREAM_XACL_DARWIN_ACCESS:
+ case STREAM_XACL_FREEBSD_DEFAULT:
+ case STREAM_XACL_FREEBSD_ACCESS:
+ case STREAM_XACL_HPUX_ACL_ENTRY:
+ case STREAM_XACL_IRIX_DEFAULT:
+ case STREAM_XACL_IRIX_ACCESS:
+ case STREAM_XACL_LINUX_DEFAULT:
+ case STREAM_XACL_LINUX_ACCESS:
+ case STREAM_XACL_TRU64_DEFAULT:
+ case STREAM_XACL_TRU64_DEFAULT_DIR:
+ case STREAM_XACL_TRU64_ACCESS:
+ case STREAM_XACL_SOLARIS_POSIX:
+ case STREAM_XACL_SOLARIS_NFS4:
+ case STREAM_XACL_AFS_TEXT:
+ case STREAM_XACL_AIX_AIXC:
+ case STREAM_XACL_AIX_NFS4:
+ case STREAM_XACL_FREEBSD_NFS4:
+ case STREAM_XACL_HURD_DEFAULT:
+ case STREAM_XACL_HURD_ACCESS:
/* Ignore Unix ACL attributes */
break;
- case STREAM_XATTR_HURD:
- case STREAM_XATTR_IRIX:
- case STREAM_XATTR_TRU64:
- case STREAM_XATTR_AIX:
- case STREAM_XATTR_OPENBSD:
- case STREAM_XATTR_SOLARIS_SYS:
- case STREAM_XATTR_SOLARIS:
- case STREAM_XATTR_DARWIN:
- case STREAM_XATTR_FREEBSD:
- case STREAM_XATTR_LINUX:
- case STREAM_XATTR_NETBSD:
+ case STREAM_XACL_HURD_XATTR:
+ case STREAM_XACL_IRIX_XATTR:
+ case STREAM_XACL_TRU64_XATTR:
+ case STREAM_XACL_AIX_XATTR:
+ case STREAM_XACL_OPENBSD_XATTR:
+ case STREAM_XACL_SOLARIS_SYS_XATTR:
+ case STREAM_XACL_SOLARIS_XATTR:
+ case STREAM_XACL_DARWIN_XATTR:
+ case STREAM_XACL_FREEBSD_XATTR:
+ case STREAM_XACL_LINUX_XATTR:
+ case STREAM_XACL_NETBSD_XATTR:
/* Ignore Unix Extended attributes */
break;
* from the stream dispatch function. Currently in this reserved space we allocate the
* different acl streams from 1000 on and the different extended attributes streams from
* 1999 down. So the two naming spaces grows towards each other.
+ *
+ * Rationalize names a bit to correspond to the new XACL classes
+ *
*/
-#define STREAM_ACL_AIX_TEXT 1000 /* AIX string of acl_get */
-#define STREAM_ACL_DARWIN_ACCESS 1001 /* Darwin (OSX) acl_t string of acl_to_text (POSIX acl) */
-#define STREAM_ACL_FREEBSD_DEFAULT 1002 /* FreeBSD acl_t string of acl_to_text (POSIX acl) for default acls */
-#define STREAM_ACL_FREEBSD_ACCESS 1003 /* FreeBSD acl_t string of acl_to_text (POSIX acl) for access acls */
-#define STREAM_ACL_HPUX_ACL_ENTRY 1004 /* HPUX acl_entry string of acltostr (POSIX acl) */
-#define STREAM_ACL_IRIX_DEFAULT 1005 /* IRIX acl_t string of acl_to_text (POSIX acl) for default acls */
-#define STREAM_ACL_IRIX_ACCESS 1006 /* IRIX acl_t string of acl_to_text (POSIX acl) for access acls */
-#define STREAM_ACL_LINUX_DEFAULT 1007 /* Linux acl_t string of acl_to_text (POSIX acl) for default acls */
-#define STREAM_ACL_LINUX_ACCESS 1008 /* Linux acl_t string of acl_to_text (POSIX acl) for access acls */
-#define STREAM_ACL_TRU64_DEFAULT 1009 /* Tru64 acl_t string of acl_to_text (POSIX acl) for default acls */
-#define STREAM_ACL_TRU64_DEFAULT_DIR 1010 /* Tru64 acl_t string of acl_to_text (POSIX acl) for default acls */
-#define STREAM_ACL_TRU64_ACCESS 1011 /* Tru64 acl_t string of acl_to_text (POSIX acl) for access acls */
-#define STREAM_ACL_SOLARIS_POSIX 1012 /* Solaris aclent_t string of acltotext or acl_totext (POSIX acl) */
-#define STREAM_ACL_SOLARIS_NFS4 1013 /* Solaris ace_t string of of acl_totext (NFSv4 or ZFS acl) */
-#define STREAM_ACL_AFS_TEXT 1014 /* AFS string of pioctl */
-#define STREAM_ACL_AIX_AIXC 1015 /* AIX string of aclx_printStr (POSIX acl) */
-#define STREAM_ACL_AIX_NFS4 1016 /* AIX string of aclx_printStr (NFSv4 acl) */
-#define STREAM_ACL_FREEBSD_NFS4 1017 /* FreeBSD acl_t string of acl_to_text (NFSv4 or ZFS acl) */
-#define STREAM_ACL_HURD_DEFAULT 1018 /* GNU HURD acl_t string of acl_to_text (POSIX acl) for default acls */
-#define STREAM_ACL_HURD_ACCESS 1019 /* GNU HURD acl_t string of acl_to_text (POSIX acl) for access acls */
-#define STREAM_XATTR_HURD 1989 /* GNU HURD extended attributes */
-#define STREAM_XATTR_IRIX 1990 /* IRIX extended attributes */
-#define STREAM_XATTR_TRU64 1991 /* TRU64 extended attributes */
-#define STREAM_XATTR_AIX 1992 /* AIX extended attributes */
-#define STREAM_XATTR_OPENBSD 1993 /* OpenBSD extended attributes */
-#define STREAM_XATTR_SOLARIS_SYS 1994 /* Solaris extensible attributes or
- * otherwise named extended system attributes.
- */
-#define STREAM_XATTR_SOLARIS 1995 /* Solaris extented attributes */
-#define STREAM_XATTR_DARWIN 1996 /* Darwin (OSX) extended attributes */
-#define STREAM_XATTR_FREEBSD 1997 /* FreeBSD extended attributes */
-#define STREAM_XATTR_LINUX 1998 /* Linux specific attributes */
-#define STREAM_XATTR_NETBSD 1999 /* NetBSD extended attributes */
+#define STREAM_XACL_AIX_TEXT 1000 /* AIX string of acl_get */
+#define STREAM_XACL_DARWIN_ACCESS 1001 /* Darwin (OSX) acl_t string of acl_to_text (POSIX acl) */
+#define STREAM_XACL_FREEBSD_DEFAULT 1002 /* FreeBSD acl_t string of acl_to_text (POSIX acl) for default acls */
+#define STREAM_XACL_FREEBSD_ACCESS 1003 /* FreeBSD acl_t string of acl_to_text (POSIX acl) for access acls */
+#define STREAM_XACL_HPUX_ACL_ENTRY 1004 /* HPUX acl_entry string of acltostr (POSIX acl) */
+#define STREAM_XACL_IRIX_DEFAULT 1005 /* IRIX acl_t string of acl_to_text (POSIX acl) for default acls */
+#define STREAM_XACL_IRIX_ACCESS 1006 /* IRIX acl_t string of acl_to_text (POSIX acl) for access acls */
+#define STREAM_XACL_LINUX_DEFAULT 1007 /* Linux acl_t string of acl_to_text (POSIX acl) for default acls */
+#define STREAM_XACL_LINUX_ACCESS 1008 /* Linux acl_t string of acl_to_text (POSIX acl) for access acls */
+#define STREAM_XACL_TRU64_DEFAULT 1009 /* Tru64 acl_t string of acl_to_text (POSIX acl) for default acls */
+#define STREAM_XACL_TRU64_DEFAULT_DIR 1010 /* Tru64 acl_t string of acl_to_text (POSIX acl) for default acls */
+#define STREAM_XACL_TRU64_ACCESS 1011 /* Tru64 acl_t string of acl_to_text (POSIX acl) for access acls */
+#define STREAM_XACL_SOLARIS_POSIX 1012 /* Solaris aclent_t string of acltotext or acl_totext (POSIX acl) */
+#define STREAM_XACL_SOLARIS_NFS4 1013 /* Solaris ace_t string of of acl_totext (NFSv4 or ZFS acl) */
+#define STREAM_XACL_AFS_TEXT 1014 /* AFS string of pioctl */
+#define STREAM_XACL_AIX_AIXC 1015 /* AIX string of aclx_printStr (POSIX acl) */
+#define STREAM_XACL_AIX_NFS4 1016 /* AIX string of aclx_printStr (NFSv4 acl) */
+#define STREAM_XACL_FREEBSD_NFS4 1017 /* FreeBSD acl_t string of acl_to_text (NFSv4 or ZFS acl) */
+#define STREAM_XACL_HURD_DEFAULT 1018 /* GNU HURD acl_t string of acl_to_text (POSIX acl) for default acls */
+#define STREAM_XACL_HURD_ACCESS 1019 /* GNU HURD acl_t string of acl_to_text (POSIX acl) for access acls */
+#define STREAM_XACL_HURD_XATTR 1989 /* GNU HURD extended attributes */
+#define STREAM_XACL_IRIX_XATTR 1990 /* IRIX extended attributes */
+#define STREAM_XACL_TRU64_XATTR 1991 /* TRU64 extended attributes */
+#define STREAM_XACL_AIX_XATTR 1992 /* AIX extended attributes */
+#define STREAM_XACL_OPENBSD_XATTR 1993 /* OpenBSD extended attributes */
+#define STREAM_XACL_SOLARIS_SYS_XATTR 1994 /* Solaris extensible attributes or
+ * otherwise named extended system attributes.
+ */
+#define STREAM_XACL_SOLARIS_XATTR 1995 /* Solaris extented attributes */
+#define STREAM_XACL_DARWIN_XATTR 1996 /* Darwin (OSX) extended attributes */
+#define STREAM_XACL_FREEBSD_XATTR 1997 /* FreeBSD extended attributes */
+#define STREAM_XACL_LINUX_XATTR 1998 /* Linux specific attributes */
+#define STREAM_XACL_NETBSD_XATTR 1999 /* NetBSD extended attributes */
/* WARNING!!! do not define more than 2047 of these old types */