]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/filed/xattr.c
Loose #ifdef and use const bool wrapper for some cleaner coding.
[bacula/bacula] / bacula / src / filed / xattr.c
index 2c8dba75d23403a77e26377d02d4bfddc0f639c7..b8b6199299db0fa46f314ce4e99703d636175484 100644 (file)
 
 #include "bacula.h"
 #include "filed.h"
-#include "xattr.h"
 
 #if !defined(HAVE_XATTR)
 /*
  * Entry points when compiled without support for XATTRs or on an unsupported platform.
  */
-bsub_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
+bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
-   return bsub_exit_fatal;
+   return bxattr_exit_fatal;
 }
 
-bsub_exit_code parse_xattr_streams(JCR *jcr, int stream)
+bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
 {
-   return bsub_exit_fatal;
+   return bxattr_exit_fatal;
 }
 #else
 /*
  * Send a XATTR stream to the SD.
  */
-static bsub_exit_code send_xattr_stream(JCR *jcr, int stream)
+static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
 {
    BSOCK *sd = jcr->store_bsock;
    POOLMEM *msgsave;
 #ifdef FD_NO_SEND_TEST
-   return bsub_exit_ok;
+   return bxattr_exit_ok;
 #endif
 
    /*
     * Sanity check
     */
-   if (jcr->xattr_data_len <= 0)
-      return bsub_exit_ok;
+   if (jcr->xattr_data->content_length <= 0) {
+      return bxattr_exit_ok;
+   }
 
    /*
     * Send header
@@ -84,22 +84,22 @@ static bsub_exit_code send_xattr_stream(JCR *jcr, int stream)
    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 bsub_exit_fatal;
+      return bxattr_exit_fatal;
    }
 
    /*
     * Send the buffer to the storage deamon
     */
-   Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data);
+   Dmsg1(400, "Backing up XATTR <%s>\n", jcr->xattr_data->content);
    msgsave = sd->msg;
-   sd->msg = jcr->xattr_data;
-   sd->msglen = jcr->xattr_data_len;
+   sd->msg = jcr->xattr_data->content;
+   sd->msglen = jcr->xattr_data->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 bsub_exit_fatal;
+      return bxattr_exit_fatal;
    }
 
    jcr->JobBytes += sd->msglen;
@@ -107,10 +107,10 @@ static bsub_exit_code send_xattr_stream(JCR *jcr, int stream)
    if (!sd->signal(BNET_EOD)) {
       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
             sd->bstrerror());
-      return bsub_exit_fatal;
+      return bxattr_exit_fatal;
    }
    Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
-   return bsub_exit_ok;
+   return bxattr_exit_ok;
 }
 
 /*
@@ -131,12 +131,20 @@ static bsub_exit_code send_xattr_stream(JCR *jcr, int stream)
  */
 #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_FREEBSD_OS)
 static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
+static const char *xattr_acl_skiplist[1] = { NULL };
+static const char *xattr_skiplist[1] = { NULL };
 #elif defined(HAVE_LINUX_OS)
 static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
+static const char *xattr_acl_skiplist[2] = { "system.posix_acl_access", NULL };
+static const char *xattr_skiplist[1] = { NULL };
 #elif defined(HAVE_NETBSD_OS)
 static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
+static const char *xattr_acl_skiplist[1] = { NULL };
+static const char *xattr_skiplist[1] = { NULL };
 #endif
 
 /*
@@ -215,8 +223,8 @@ static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len
     * Make sure the serialized stream fits in the poolmem buffer.
     * We allocate some more to be sure the stream is gonna fit.
     */
-   jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, expected_serialize_len + 10);
-   ser_begin(jcr->xattr_data, expected_serialize_len + 10);
+   jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, expected_serialize_len + 10);
+   ser_begin(jcr->xattr_data->content, expected_serialize_len + 10);
 
    /*
     * Walk the list of xattrs and serialize the data.
@@ -236,20 +244,21 @@ static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len
       ser_bytes(current_xattr->value, current_xattr->value_length);
    }
 
-   ser_end(jcr->xattr_data, expected_serialize_len + 10);
-   jcr->xattr_data_len = ser_length(jcr->xattr_data);
-   return jcr->xattr_data_len;
+   ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
+   jcr->xattr_data->content_length = ser_length(jcr->xattr_data->content);
+   return jcr->xattr_data->content_length;
 }
 
-static bsub_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
+static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
-   int count = 0;
+   bool skip_xattr;
+   int cnt, xattr_count = 0;
    int32_t xattr_list_len,
            xattr_value_len;
    uint32_t expected_serialize_len = 0;
    char *xattr_list, *bp;
    xattr_t *xattr_value_list = NULL, *current_xattr;
-   bsub_exit_code retval = bsub_exit_nok;
+   bxattr_exit_code retval = bxattr_exit_error;
    berrno be;
 
    /*
@@ -259,16 +268,16 @@ static bsub_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
    if (xattr_list_len < 0) {
       switch (errno) {
       case ENOENT:
-         return bsub_exit_ok;
+         return bxattr_exit_ok;
       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 bsub_exit_nok;
+         return bxattr_exit_error;
       }
    } else if (xattr_list_len == 0) {
-      return bsub_exit_ok;
+      return bxattr_exit_ok;
    }
 
    /*
@@ -284,7 +293,7 @@ static bsub_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
    if (xattr_list_len < 0) {
       switch (errno) {
       case ENOENT:
-         retval = bsub_exit_ok;
+         retval = bxattr_exit_ok;
          goto bail_out;
       default:
          Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
@@ -301,23 +310,42 @@ static bsub_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
     */
    bp = xattr_list;
    while ((bp - xattr_list) + 1 < xattr_list_len) {
-#if defined(HAVE_LINUX_OS)
+      skip_xattr = false;
+
       /*
-       * On Linux you also get the acls in the extented attribute list.
+       * 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) == 0 || strcmp(bp, "system.posix_acl_access"))
-         count++;
-#else
-      count++;
-#endif
+      if (ff_pkt->flags & FO_ACL) {
+         for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
+            if (!strcmp(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 (!strcmp(bp, xattr_skiplist[cnt])) {
+               skip_xattr = true;
+               break;
+            }
+         }
+      }
+
+      if (!skip_xattr) {
+         xattr_count++;
+      }
       bp = strchr(bp, '\0') + 1;
    }
 
-   if (count == 0) {
-      retval = bsub_exit_ok;
+   if (xattr_count == 0) {
+      retval = bxattr_exit_ok;
       goto bail_out;
    }
 
@@ -325,8 +353,8 @@ static bsub_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
     * Allocate enough room to hold all extended attributes.
     * After allocating the storage make sure its empty by zeroing it.
     */
-   xattr_value_list = (xattr_t *)malloc(count * sizeof(xattr_t));
-   memset((caddr_t)xattr_value_list, 0, count * sizeof(xattr_t));
+   xattr_value_list = (xattr_t *)malloc(xattr_count * sizeof(xattr_t));
+   memset((caddr_t)xattr_value_list, 0, xattr_count * sizeof(xattr_t));
 
    /*
     * Walk the list of extended attributes names and retrieve the data.
@@ -335,17 +363,38 @@ static bsub_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
    current_xattr = xattr_value_list;
    bp = xattr_list;
    while ((bp - xattr_list) + 1 < xattr_list_len) {
-#if defined(HAVE_LINUX_OS)
+      skip_xattr = false;
+
       /*
-       * On Linux you also get the acls in the extented attribute list.
+       * 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 && !strcmp(bp, "system.posix_acl_access")) {
+      if (ff_pkt->flags & FO_ACL) {
+         for (cnt = 0; xattr_acl_skiplist[cnt] != NULL; cnt++) {
+            if (!strcmp(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 (!strcmp(bp, xattr_skiplist[cnt])) {
+               skip_xattr = true;
+               break;
+            }
+         }
+      }
+
+      if (!skip_xattr) {
          bp = strchr(bp, '\0') + 1;
          continue;
       }
-#endif
 
       /*
        * Each xattr valuepair starts with a magic so we can parse it easier.
@@ -369,7 +418,7 @@ static bsub_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
       if (xattr_value_len < 0) {
          switch (errno) {
          case ENOENT:
-            retval = bsub_exit_ok;
+            retval = bxattr_exit_ok;
             goto bail_out;
          default:
             Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
@@ -390,7 +439,7 @@ static bsub_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
       if (xattr_value_len < 0) {
          switch (errno) {
          case ENOENT:
-            retval = bsub_exit_ok;
+            retval = bxattr_exit_ok;
             goto bail_out;
          default:
             Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
@@ -450,11 +499,11 @@ bail_out:
    return retval;
 }
 
-static bsub_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
+static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
 {
    unser_declare;
    xattr_t current_xattr;
-   bsub_exit_code retval = bsub_exit_ok;
+   bxattr_exit_code retval = bxattr_exit_ok;
    berrno be;
 
    /*
@@ -463,8 +512,8 @@ static bsub_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
     * Start unserializing the data. We keep on looping while we have not
     * unserialized all bytes in the stream.
     */
-   unser_begin(jcr->xattr_data, jcr->xattr_data_len);
-   while (unser_length(jcr->xattr_data) < jcr->xattr_data_len) {
+   unser_begin(jcr->xattr_data->content, jcr->xattr_data->content_length);
+   while (unser_length(jcr->xattr_data->content) < jcr->xattr_data->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.
@@ -475,7 +524,7 @@ static bsub_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
                jcr->last_fname);
          Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
                jcr->last_fname);
-         return bsub_exit_nok;
+         return bxattr_exit_error;
       }
 
       /*
@@ -520,7 +569,7 @@ static bsub_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
                   jcr->last_fname, be.bstrerror());
             Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
                   jcr->last_fname, be.bstrerror());
-            retval = bsub_exit_nok;
+            retval = bxattr_exit_error;
             break;
          }
       }
@@ -532,15 +581,15 @@ static bsub_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
       free(current_xattr.value);
    }
 
-   unser_end(jcr->xattr_data, jcr->xattr_data_len);
+   unser_end(jcr->xattr_data->content, jcr->xattr_data->content_length);
    return retval;
 }
 
 /*
  * For all these os-es setup the build and parse function pointer to the generic functions.
  */
-static bsub_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
-static bsub_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
+static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
+static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
 
 #elif defined(HAVE_SUN_OS)
 /*
@@ -647,27 +696,15 @@ static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SO
 static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
 #endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
 
-/*
- * This is the count of xattrs saved on a certain file, it gets reset
- * on each new file processed and is used to see if we need to send
- * the hidden xattr dir data. We only send that data when we encounter
- * an other xattr on the file.
- */
-static int nr_xattr_saved = 0;
-static char toplevel_hidden_dir_xattr_data[MAXSTRING];
-static int toplevel_hidden_dir_xattr_data_len;
-
 /*
  * 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 alist *xattr_link_cache = NULL;
-
-static struct xattr_link_cache_entry *find_xattr_link_cache_entry(ino_t inum)
+static xattr_link_cache_entry_t *find_xattr_link_cache_entry(JCR *jcr, ino_t inum)
 {
    xattr_link_cache_entry_t *ptr;
 
-   foreach_alist(ptr, xattr_link_cache) {
+   foreach_alist(ptr, jcr->xattr_data->link_cache) {
       if (ptr && ptr->inum == inum) {
          return ptr;
       }
@@ -675,15 +712,15 @@ static struct xattr_link_cache_entry *find_xattr_link_cache_entry(ino_t inum)
    return NULL;
 }
 
-static void add_xattr_link_cache_entry(ino_t inum, char *target)
+static 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(struct xattr_link_cache_entry));
-   memset((caddr_t)ptr, 0, sizeof(struct xattr_link_cache_entry));
+   ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
+   memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
    ptr->inum = inum;
    bstrncpy(ptr->target, target, sizeof(ptr->target));
-   xattr_link_cache->append(ptr);
+   jcr->xattr_data->link_cache->append(ptr);
 }
 
 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
@@ -781,7 +818,7 @@ static bool acl_is_trivial(int count, aclent_t *entries)
 }
 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
 
-static bsub_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
+static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
 {
 #ifdef HAVE_ACL
 #ifdef HAVE_EXTENDED_ACL
@@ -801,13 +838,13 @@ static bsub_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrn
            acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
          switch (errno) {
          case ENOENT:
-            return bsub_exit_ok;
+            return bxattr_exit_ok;
          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_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
                   attrname, jcr->last_fname, be.bstrerror());
-            return bsub_exit_nok;
+            return bxattr_exit_error;
          }
       }
 
@@ -829,7 +866,7 @@ static bsub_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrn
    } else {
       *acl_text = NULL;
    }
-   return bsub_exit_ok;
+   return bxattr_exit_ok;
 #else /* HAVE_EXTENDED_ACL */
    int n;
    aclent_t *acls = NULL;
@@ -851,14 +888,14 @@ static bsub_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrn
          switch (errno) {
          case ENOENT:
             free(acls);
-            return bsub_exit_ok;
+            return bxattr_exit_ok;
          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);
-            return bsub_exit_nok;
+            return bxattr_exit_error;
          }
       }
 
@@ -872,7 +909,7 @@ static bsub_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrn
             Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
                   attrname, jcr->last_fname, be.bstrerror());
             free(acls);
-            return bsub_exit_nok;
+            return bxattr_exit_error;
          }
       } else {
          *acl_text = NULL;
@@ -882,18 +919,18 @@ static bsub_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrn
    } else {
       *acl_text = NULL;
    }
-   return bsub_exit_ok;
+   return bxattr_exit_ok;
 #endif /* HAVE_EXTENDED_ACL */
 
 #else /* HAVE_ACL */
-   return bsub_exit_ok;
+   return bxattr_exit_ok;
 #endif /* HAVE_ACL */
 }
 
 /*
  * Forward declaration for recursive function call.
  */
-static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
+static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
 
 /*
  * Save an extended or extensible attribute.
@@ -910,19 +947,19 @@ static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace,
  * acl_string is an acl text when a non trivial acl is set on the xattr.
  * actual_xattr_data is the content of the xattr file.
  */
-static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
-                                         const char *attrname, bool toplevel_hidden_dir, int stream)
+static bxattr_exit_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;
-   struct xattr_link_cache_entry *xlce;
+   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[BUFSIZ];
-   bsub_exit_code retval = bsub_exit_nok;
+   bxattr_exit_code retval = bxattr_exit_error;
    berrno be;
 
    bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
@@ -933,7 +970,7 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
    if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
       switch (errno) {
       case ENOENT:
-         retval = bsub_exit_ok;
+         retval = bxattr_exit_ok;
          goto bail_out;
       default:
          Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
@@ -956,7 +993,7 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
       /*
        * Get any acl on the xattr.
        */
-      if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bsub_exit_ok)
+      if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
          goto bail_out;
 
       /*
@@ -967,12 +1004,11 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
       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) != bsub_exit_ok)
+      if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
          goto bail_out;
 
       /*
@@ -980,15 +1016,17 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
        */
       if (toplevel_hidden_dir) {
          /*
-          * Save the data for later storage when we encounter a real xattr.
-          * Encode the stat struct into an ASCII representation and jump out of the function.
+          * Save the data for later storage when we encounter a real xattr. We store the data
+          * in the jcr->xattr_data->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, 0, stream);
-         toplevel_hidden_dir_xattr_data_len = bsnprintf(toplevel_hidden_dir_xattr_data,
-                                                        sizeof(toplevel_hidden_dir_xattr_data),
-                                                        "%s%c%s%c%s%c",
-                                                        target_attrname, 0, attribs, 0,
-                                                        (acl_text) ? acl_text : "", 0);
+         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_data->content, buffer, cnt);
+         jcr->xattr_data->content_length = cnt;
          goto bail_out;
       } else {
          /*
@@ -1009,7 +1047,7 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
          /*
           * See if the cache already knows this inode number.
           */
-         if ((xlce = find_xattr_link_cache_entry(st.st_ino)) != NULL) {
+         if ((xlce = find_xattr_link_cache_entry(jcr, st.st_ino)) != NULL) {
             /*
              * Generate a xattr encoding with the reference to the target in there.
              */
@@ -1017,8 +1055,8 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
             cnt = bsnprintf(buffer, sizeof(buffer),
                             "%s%c%s%c%s%c",
                             target_attrname, 0, attribs, 0, xlce->target, 0);
-            pm_memcpy(jcr->xattr_data, buffer, cnt);
-            jcr->xattr_data_len = cnt;
+            pm_memcpy(jcr->xattr_data->content, buffer, cnt);
+            jcr->xattr_data->content_length = cnt;
             retval = send_xattr_stream(jcr, stream);
 
             /*
@@ -1031,13 +1069,13 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
           * Store this hard linked file in the cache.
           * Store the name relative to the top level xattr space.
           */
-         add_xattr_link_cache_entry(st.st_ino, target_attrname + 1);
+         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) != bsub_exit_ok) {
+      if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
          goto bail_out;
       }
 
@@ -1055,7 +1093,7 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
       if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
          switch (errno) {
          case ENOENT:
-            retval = bsub_exit_ok;
+            retval = bxattr_exit_ok;
             goto bail_out;
          default:
             Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
@@ -1066,7 +1104,6 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
          }
       }
       break;
-
    case S_IFLNK:
       /*
        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
@@ -1075,7 +1112,7 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
       if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
          switch (errno) {
          case ENOENT:
-            retval = bsub_exit_ok;
+            retval = bxattr_exit_ok;
             goto bail_out;
          default:
             Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
@@ -1093,30 +1130,37 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
       cnt = bsnprintf(buffer, sizeof(buffer),
                       "%s%c%s%c%s%c",
                       target_attrname, 0, attribs, 0, link_source, 0);
-      pm_memcpy(jcr->xattr_data, buffer, cnt);
-      jcr->xattr_data_len = cnt;
+      pm_memcpy(jcr->xattr_data->content, buffer, cnt);
+      jcr->xattr_data->content_length = cnt;
       retval = send_xattr_stream(jcr, stream);
 
+      if (retval == bxattr_exit_ok) {
+         jcr->xattr_data->nr_saved++;
+      }
+
       /*
        * For a soft linked file we are ready now, no need to recursively save the attributes.
        */
       goto bail_out;
-
    default:
       goto bail_out;
    }
 
    /*
-    * See if this is the first real xattr being saved. If it is save the toplevel_hidden_dir attributes first.
+    * 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_data->content buffer.
     */
-   if (nr_xattr_saved == 0) {
-      pm_memcpy(jcr->xattr_data, toplevel_hidden_dir_xattr_data, toplevel_hidden_dir_xattr_data_len);
-      jcr->xattr_data_len = toplevel_hidden_dir_xattr_data_len;
+   if (jcr->xattr_data->nr_saved == 0) {
       retval = send_xattr_stream(jcr, STREAM_XATTR_SOLARIS);
+      if (retval != bxattr_exit_ok) {
+         goto bail_out;
+      }
+      jcr->xattr_data->nr_saved++;
    }
 
-   pm_memcpy(jcr->xattr_data, buffer, cnt);
-   jcr->xattr_data_len = cnt;
+   pm_memcpy(jcr->xattr_data->content, buffer, cnt);
+   jcr->xattr_data->content_length = cnt;
 
    /*
     * Only dump the content of regular files.
@@ -1134,9 +1178,9 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
          }
 
          while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
-            jcr->xattr_data = check_pool_memory_size(jcr->xattr_data, jcr->xattr_data_len + cnt);
-            memcpy(jcr->xattr_data + jcr->xattr_data_len, buffer, cnt);
-            jcr->xattr_data_len += cnt;
+            jcr->xattr_data->content = check_pool_memory_size(jcr->xattr_data->content, jcr->xattr_data->content_length + cnt);
+            memcpy(jcr->xattr_data->content + jcr->xattr_data->content_length, buffer, cnt);
+            jcr->xattr_data->content_length += cnt;
          }
 
          if (cnt < 0) {
@@ -1155,7 +1199,9 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
 
    if (retval) {
       retval = send_xattr_stream(jcr, stream);
-      nr_xattr_saved++;
+      if (retval == bxattr_exit_ok) {
+         jcr->xattr_data->nr_saved++;
+      }
    }
 
    /*
@@ -1171,7 +1217,7 @@ static bsub_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_nam
       if (fchdir(fd) < 0) {
          switch (errno) {
          case ENOENT:
-            retval = bsub_exit_ok;
+            retval = bxattr_exit_ok;
             goto bail_out;
          default:
             Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
@@ -1193,14 +1239,14 @@ bail_out:
    return retval;
 }
 
-static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
+static bxattr_exit_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];
-   bsub_exit_code retval = bsub_exit_nok;
+   bxattr_exit_code retval = bxattr_exit_error;
    berrno be;
  
    /*
@@ -1227,7 +1273,7 @@ static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace,
    if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
       switch (errno) {
       case ENOENT:
-         retval = bsub_exit_ok;
+         retval = bxattr_exit_ok;
          goto bail_out;
       default:
          Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
@@ -1249,10 +1295,10 @@ static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace,
           * 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 = bsub_exit_ok;
+         retval = bxattr_exit_ok;
          goto bail_out;
       case ENOENT:
-         retval = bsub_exit_ok;
+         retval = bxattr_exit_ok;
          goto bail_out;
       default:
          Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
@@ -1282,7 +1328,7 @@ static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace,
     */
    if (!attr_parent)
       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
-                            true, STREAM_XATTR_SOLARIS);
+                         true, STREAM_XATTR_SOLARIS);
 
    if ((fd = dup(attrdirfd)) == -1 ||
        (dirp = fdopendir(fd)) == (DIR *)NULL) {
@@ -1343,7 +1389,7 @@ static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace,
           * Save the xattr.
           */
          solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
-                               false, STREAM_XATTR_SOLARIS_SYS);
+                            false, STREAM_XATTR_SOLARIS_SYS);
          continue;
       }
 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
@@ -1352,11 +1398,11 @@ static bsub_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace,
        * Save the xattr.
        */
       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
-                            false, STREAM_XATTR_SOLARIS);
+                         false, STREAM_XATTR_SOLARIS);
    }
 
    closedir(dirp);
-   retval = bsub_exit_ok;
+   retval = bxattr_exit_ok;
 
 bail_out:
    if (attrdirfd != -1)
@@ -1367,7 +1413,7 @@ bail_out:
 }
 
 #ifdef HAVE_ACL
-static bsub_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
+static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
 {
 #ifdef HAVE_EXTENDED_ACL
    int error;
@@ -1377,7 +1423,7 @@ static bsub_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *at
    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 bsub_exit_nok;
+      return bxattr_exit_error;
    }
 
    if ((fd != -1 && facl_set(fd, aclp) != 0) ||
@@ -1386,13 +1432,13 @@ static bsub_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *at
             attrname, jcr->last_fname, be.bstrerror());
       Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
             attrname, jcr->last_fname, be.bstrerror());
-      return bsub_exit_nok;
+      return bxattr_exit_error;
    }
 
    if (aclp) {
       acl_free(aclp);
    }
-   return bsub_exit_ok;
+   return bxattr_exit_ok;
 
 #else /* HAVE_EXTENDED_ACL */
    int n;
@@ -1407,21 +1453,21 @@ static bsub_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *at
                attrname, jcr->last_fname, be.bstrerror());
          Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
                attrname, jcr->last_fname, be.bstrerror());
-         return bsub_exit_nok;
+         return bxattr_exit_error;
       }
    }
 
    if (acls) {
       free(acls);
    }
-   return bsub_exit_ok;
+   return bxattr_exit_ok;
 
 #endif /* HAVE_EXTENDED_ACL */
 
 }
 #endif /* HAVE_ACL */
 
-static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
+static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
 {
    int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
    int used_bytes, total_bytes, cnt;
@@ -1432,23 +1478,23 @@ static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
    int32_t inum;
    struct stat st;
    struct timeval times[2];
-   bsub_exit_code retval = bsub_exit_nok;
+   bxattr_exit_code retval = bxattr_exit_error;
    berrno be;
 
    /*
     * Parse the xattr stream. First the part that is the same for all xattrs.
     */
    used_bytes = 0;
-   total_bytes = jcr->xattr_data_len;
+   total_bytes = jcr->xattr_data->content_length;
 
    /*
     * 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 = jcr->xattr_data + 1;
+   target_attrname = jcr->xattr_data->content + 1;
    if ((bp = strchr(target_attrname, '\0')) == (char *)NULL ||
-       (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
+       (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
       goto parse_error;
    }
    attribs = ++bp;
@@ -1539,7 +1585,7 @@ static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
     * Decode the next field (acl_text).
     */
    if ((bp = strchr(attribs, '\0')) == (char *)NULL ||
-       (used_bytes = (bp - jcr->xattr_data)) >= (total_bytes - 1)) {
+       (used_bytes = (bp - jcr->xattr_data->content)) >= (total_bytes - 1)) {
       goto parse_error;
    }
    acl_text = ++bp;
@@ -1612,11 +1658,11 @@ static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
          /*
           * Successfully restored xattr.
           */
-         retval = bsub_exit_ok;
+         retval = bxattr_exit_ok;
          goto bail_out;
       } else {
          if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
-             (used_bytes = (bp - jcr->xattr_data)) >= total_bytes) {
+             (used_bytes = (bp - jcr->xattr_data->content)) >= total_bytes) {
             goto parse_error;
          }
 
@@ -1643,7 +1689,7 @@ static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
        * Restore the actual data.
        */
       if (st.st_size > 0) {
-         used_bytes = (data - jcr->xattr_data);
+         used_bytes = (data - jcr->xattr_data->content);
          cnt = total_bytes - used_bytes;
 
          /*
@@ -1691,7 +1737,7 @@ static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
       /*
        * Successfully restored xattr.
        */
-      retval = bsub_exit_ok;
+      retval = bxattr_exit_ok;
       goto bail_out;
    default:
       goto bail_out;
@@ -1708,10 +1754,10 @@ static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
              * Gentile way of the system saying this type of xattr layering is not supported.
              * But as this is not an error we return a positive return value.
              */
-            retval = bsub_exit_ok;
+            retval = bxattr_exit_ok;
             break;
          case ENOENT:
-            retval = bsub_exit_ok;
+            retval = bxattr_exit_ok;
             break;
          default:
             Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
@@ -1725,7 +1771,7 @@ static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
 
 #ifdef HAVE_ACL
    if (acl_text && *acl_text)
-      if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bsub_exit_ok)
+      if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
          goto bail_out;
 #endif /* HAVE_ACL */
 
@@ -1750,7 +1796,7 @@ static bsub_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
    /*
     * Successfully restored xattr.
     */
-   retval = bsub_exit_ok;
+   retval = bxattr_exit_ok;
    goto bail_out;
 
 parse_error:
@@ -1772,37 +1818,37 @@ bail_out:
    return retval;
 }
 
-static bsub_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
+static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    char cwd[PATH_MAX];
-   bsub_exit_code retval = bsub_exit_ok;
+   bxattr_exit_code retval = bxattr_exit_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) {
-      nr_xattr_saved = 0;
+      jcr->xattr_data->nr_saved = 0;
+      jcr->xattr_data->link_cache = New(alist(10, not_owned_by_alist));
 
       /*
        * As we change the cwd in the save function save the current cwd
        * for restore after return from the solaris_save_xattrs function.
        */
-      xattr_link_cache = New(alist(10, not_owned_by_alist));
       getcwd(cwd, sizeof(cwd));
       retval = solaris_save_xattrs(jcr, NULL, NULL);
       chdir(cwd);
-      delete xattr_link_cache;
-      xattr_link_cache = NULL;
+      delete jcr->xattr_data->link_cache;
+      jcr->xattr_data->link_cache = NULL;
    }
    return retval;
 }
 
-static bsub_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
+static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
 {
    char cwd[PATH_MAX];
    bool is_extensible = false;
-   bsub_exit_code retval;
+   bxattr_exit_code retval;
 
    /*
     * First make sure we can restore xattr on the filesystem.
@@ -1816,7 +1862,7 @@ static bsub_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
                jcr->last_fname);
          Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
             jcr->last_fname);
-         return bsub_exit_nok;
+         return bxattr_exit_error;
       }
 
       is_extensible = true;
@@ -1829,11 +1875,11 @@ static bsub_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
                jcr->last_fname);
          Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
             jcr->last_fname);
-         return bsub_exit_nok;
+         return bxattr_exit_error;
       }
       break;
    default:
-      return bsub_exit_nok;
+      return bxattr_exit_error;
    }
 
    /*
@@ -1850,25 +1896,25 @@ static bsub_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
 /*
  * Function pointers to the build and parse function to use for these xattrs.
  */
-static bsub_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
-static bsub_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
+static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
+static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
 
 #endif /* defined(HAVE_SUN_OS) */
 
 /*
  * Entry points when compiled with support for XATTRs on a supported platform.
  */
-bsub_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
+bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    if (os_build_xattr_streams) {
       return (*os_build_xattr_streams)(jcr, ff_pkt);
    }
-   return bsub_exit_nok;
+   return bxattr_exit_error;
 }
 
-bsub_exit_code parse_xattr_streams(JCR *jcr, int stream)
+bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
 {
-   int cnt;
+   unsigned int cnt;
 
    if (os_parse_xattr_streams) {
       /*
@@ -1886,6 +1932,6 @@ bsub_exit_code parse_xattr_streams(JCR *jcr, int stream)
    Jmsg2(jcr, M_WARNING, 0,
       _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
       jcr->last_fname, stream);
-   return bsub_exit_nok;
+   return bxattr_exit_error;
 }
 #endif