]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/filed/xattr.c
Rename bEventVssSnapshotLetters to bEventPrepareSnapshot
[bacula/bacula] / bacula / src / filed / xattr.c
index 6a839d201bd211aef99277f6f946b624706a2687..5781e76feb44bf136ef0b111d33fd8e07c5d5dc7 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2008-2009 Free Software Foundation Europe e.V.
+   Copyright (C) 2008-2010 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    This program is Free Software; you can redistribute it and/or
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
+   modify it under the terms of version three of the GNU Affero General Public
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
@@ -15,7 +15,7 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Affero General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
 */
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
 */
-/*
+/**
  * Functions to handle Extended Attributes for bacula.
  *
  * Extended Attributes are so OS specific we only restore Extended Attributes if
  * they were saved using a filed on the same platform.
  *
  * Currently we support the following OSes:
  * 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)
  *   - Darwin (Extended Attributes)
+ *   - FreeBSD (Extended Attributes)
+ *   - IRIX (Extended Attributes)
  *   - Linux (Extended Attributes)
  *   - NetBSD (Extended Attributes)
  *   - Linux (Extended Attributes)
  *   - NetBSD (Extended Attributes)
- *   - FreeBSD (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
  *   - 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
  *      might eventually support xattr on OpenBSD when they implemented them using
  *      the same interface as FreeBSD and NetBSD.
  *   - Solaris (Extended Attributes and Extensible Attributes)
  *      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 MMVIII
  *
  *   Written by Marco van Wieringen, November MMVIII
- *
  */
 
 #include "bacula.h"
 #include "filed.h"
 
 #if !defined(HAVE_XATTR)
  */
 
 #include "bacula.h"
 #include "filed.h"
 
 #if !defined(HAVE_XATTR)
-/*
+/**
  * Entry points when compiled without support for XATTRs or on an unsupported platform.
  */
 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
  * Entry points when compiled without support for XATTRs or on an unsupported platform.
  */
 bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
@@ -65,7 +67,7 @@ bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
    return bxattr_exit_fatal;
 }
 #else
    return bxattr_exit_fatal;
 }
 #else
-/*
+/**
  * Send a XATTR stream to the SD.
  */
 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
  * Send a XATTR stream to the SD.
  */
 static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
@@ -118,15 +120,11 @@ static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
    return bxattr_exit_ok;
 }
 
    return bxattr_exit_ok;
 }
 
-/*
+/**
  * First some generic functions for OSes that use the same xattr encoding scheme.
  * First some generic functions for OSes that use the same xattr encoding scheme.
+ * Currently for all OSes except for Solaris.
  */
  */
-#if defined(HAVE_DARWIN_OS) || \
-    defined(HAVE_LINUX_OS) || \
-    defined(HAVE_NETBSD_OS) || \
-    defined(HAVE_FREEBSD_OS) || \
-    defined(HAVE_OPENBSD_OS)
-
+#if !defined(HAVE_SUN_OS)
 static void xattr_drop_internal_table(alist *xattr_value_list)
 {
    xattr_t *current_xattr;
 static void xattr_drop_internal_table(alist *xattr_value_list)
 {
    xattr_t *current_xattr;
@@ -145,12 +143,14 @@ static void xattr_drop_internal_table(alist *xattr_value_list)
 
       if (current_xattr->value_length > 0)
          free(current_xattr->value);
 
       if (current_xattr->value_length > 0)
          free(current_xattr->value);
+
+      free(current_xattr);
    }
 
    delete xattr_value_list;
 }
 
    }
 
    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 xattr stream for OSX, FreeBSD, Linux and NetBSD is a serialized stream of bytes
  * which encodes one or more xattr_t structures.
  *
@@ -191,7 +191,14 @@ static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len
       ser_bytes(current_xattr->name, current_xattr->name_length);
 
       ser_uint32(current_xattr->value_length);
       ser_bytes(current_xattr->name, current_xattr->name_length);
 
       ser_uint32(current_xattr->value_length);
-      ser_bytes(current_xattr->value, current_xattr->value_length);
+      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_data->content, expected_serialize_len + 10);
    }
 
    ser_end(jcr->xattr_data->content, expected_serialize_len + 10);
@@ -206,7 +213,7 @@ static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_li
    xattr_t *current_xattr;
    bxattr_exit_code retval = bxattr_exit_ok;
 
    xattr_t *current_xattr;
    bxattr_exit_code retval = bxattr_exit_ok;
 
-   /*
+   /**
     * Parse the stream and call restore_xattr_on_file for each extended attribute.
     *
     * Start unserializing the data. We keep on looping while we have not
     * Parse the stream and call restore_xattr_on_file for each extended attribute.
     *
     * Start unserializing the data. We keep on looping while we have not
@@ -218,7 +225,6 @@ static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_li
        * 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.
        */
        * 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) {
       current_xattr = (xattr_t *)malloc(sizeof(xattr_t));
       unser_uint32(current_xattr->magic);
       if (current_xattr->magic != XATTR_MAGIC) {
@@ -234,6 +240,14 @@ static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_li
        * Decode the valuepair. First decode the length of the name.
        */
       unser_uint32(current_xattr->name_length);
        * 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, _("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(current_xattr);
+         return bxattr_exit_error;
+      }
 
       /*
        * Allocate room for the name and decode its content.
 
       /*
        * Allocate room for the name and decode its content.
@@ -242,7 +256,7 @@ static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_li
       unser_bytes(current_xattr->name, current_xattr->name_length);
 
       /*
       unser_bytes(current_xattr->name, current_xattr->name_length);
 
       /*
-       * The xattr_name needs to be null terminated for lsetxattr.
+       * The xattr_name needs to be null terminated.
        */
       current_xattr->name[current_xattr->name_length] = '\0';
 
        */
       current_xattr->name[current_xattr->name_length] = '\0';
 
@@ -251,11 +265,19 @@ static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_li
        */
       unser_uint32(current_xattr->value_length);
 
        */
       unser_uint32(current_xattr->value_length);
 
-      /*
-       * 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);
+      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);
    }
 
       xattr_value_list->append(current_xattr);
    }
@@ -268,68 +290,48 @@ static bxattr_exit_code unserialize_xattr_stream(JCR *jcr, alist *xattr_value_li
 /*
  * This is a supported OS, See what kind of interface we should use.
  */
 /*
  * This is a supported OS, See what kind of interface we should use.
  */
-#if defined(HAVE_DARWIN_OS) || \
-    defined(HAVE_LINUX_OS)
+#if defined(HAVE_AIX_OS)
 
 
-#if (!defined(HAVE_LISTXATTR) && !defined(HAVE_LLISTXATTR)) || \
-    (!defined(HAVE_GETXATTR) && !defined(HAVE_LGETXATTR)) || \
-    (!defined(HAVE_SETXATTR) && !defined(HAVE_LSETXATTR))
-#error "Missing either full support for the LXATTR or XATTR functions."
+#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
 
 #endif
 
-#ifdef HAVE_SYS_XATTR_H
-#include <sys/xattr.h>
+#ifdef HAVE_SYS_EA_H
+#include <sys/ea.h>
 #else
 #else
-#error "Missing sys/xattr.h header file"
+#error "Missing sys/ea.h header file"
 #endif
 
 /*
  * Define the supported XATTR streams for this OS
  */
 #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[2] = { "system.posix_acl_access", NULL };
-static const char *xattr_skiplist[1] = { NULL };
-#endif
+static int os_default_xattr_streams[1] = { STREAM_XATTR_AIX };
 
 /*
 
 /*
- * 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.
+ * Fallback to the non l-functions when those are not available.
  */
  */
-#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
+#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
 
 #endif
 
-static bxattr_exit_code linux_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
+static bxattr_exit_code aix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    bool skip_xattr;
    char *xattr_list, *bp;
    int cnt, xattr_count = 0;
 {
    bool skip_xattr;
    char *xattr_list, *bp;
    int cnt, xattr_count = 0;
+   uint32_t name_length;
    int32_t xattr_list_len,
            xattr_value_len;
    uint32_t expected_serialize_len = 0;
    int32_t xattr_list_len,
            xattr_value_len;
    uint32_t expected_serialize_len = 0;
-   xattr_t *current_xattr;
+   xattr_t *current_xattr = NULL;
    alist *xattr_value_list = NULL;
    bxattr_exit_code retval = bxattr_exit_error;
    berrno be;
    alist *xattr_value_list = NULL;
    bxattr_exit_code retval = bxattr_exit_error;
    berrno be;
@@ -337,20 +339,26 @@ static bxattr_exit_code linux_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
    /*
     * First get the length of the available list with extended attributes.
     */
    /*
     * First get the length of the available list with extended attributes.
     */
-   xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
-   if (xattr_list_len < 0) {
+   xattr_list_len = llistea(jcr->last_fname, NULL, 0);
+   switch (xattr_list_len) {
+   case -1:
       switch (errno) {
       case ENOENT:
       switch (errno) {
       case ENOENT:
+      case EFORMAT:
+      case ENOTSUP:
          return bxattr_exit_ok;
       default:
          return bxattr_exit_ok;
       default:
-         Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
+         Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
                jcr->last_fname, be.bstrerror());
                jcr->last_fname, be.bstrerror());
-         Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
+         Dmsg2(100, "llistea error file=%s ERR=%s\n",
                jcr->last_fname, be.bstrerror());
          return bxattr_exit_error;
       }
                jcr->last_fname, be.bstrerror());
          return bxattr_exit_error;
       }
-   } else if (xattr_list_len == 0) {
+      break;
+   case 0:
       return bxattr_exit_ok;
       return bxattr_exit_ok;
+   default:
+      break;
    }
 
    /*
    }
 
    /*
@@ -362,24 +370,28 @@ static bxattr_exit_code linux_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
    /*
     * Get the actual list of extended attributes names for a file.
     */
    /*
     * 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) {
+   xattr_list_len = llistea(jcr->last_fname, xattr_list, xattr_list_len);
+   switch (xattr_list_len) {
+   case -1:
       switch (errno) {
       case ENOENT:
       switch (errno) {
       case ENOENT:
+      case EFORMAT:
+      case ENOTSUP:
          retval = bxattr_exit_ok;
          goto bail_out;
       default:
          retval = bxattr_exit_ok;
          goto bail_out;
       default:
-         Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
+         Mmsg2(jcr->errmsg, _("llistea error on file \"%s\": ERR=%s\n"),
                jcr->last_fname, be.bstrerror());
                jcr->last_fname, be.bstrerror());
-         Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
+         Dmsg2(100, "llistea error file=%s ERR=%s\n",
                jcr->last_fname, be.bstrerror());
          goto bail_out;
       }
                jcr->last_fname, be.bstrerror());
          goto bail_out;
       }
+      break;
+   default:
+      break;
    }
    xattr_list[xattr_list_len] = '\0';
 
    }
    xattr_list[xattr_list_len] = '\0';
 
-   xattr_value_list = New(alist(10, not_owned_by_alist));
-
    /*
     * Walk the list of extended attributes names and retrieve the data.
     * We already count the bytes needed for serializing the stream later on.
    /*
     * Walk the list of extended attributes names and retrieve the data.
     * We already count the bytes needed for serializing the stream later on.
@@ -389,32 +401,15 @@ static bxattr_exit_code linux_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
       skip_xattr = false;
 
       /*
       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.
+       * We want to skip certain xattrs which start with a 0xF8 character on AIX.
        */
        */
-      if (!skip_xattr) {
-         for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
-            if (bstrcmp(bp, xattr_skiplist[cnt])) {
-               skip_xattr = true;
-               break;
-            }
-         }
+      if (*bp == 0xF8) {
+         skip_xattr = true;
       }
 
       }
 
-      if (skip_xattr) {
+      name_length = strlen(bp);
+      if (skip_xattr || name_length == 0) {
+         Dmsg1(100, "Skipping xattr named %s\n", bp);
          bp = strchr(bp, '\0') + 1;
          continue;
       }
          bp = strchr(bp, '\0') + 1;
          continue;
       }
@@ -429,7 +424,7 @@ static bxattr_exit_code linux_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
       /*
        * Allocate space for storing the name.
        */
       /*
        * Allocate space for storing the name.
        */
-      current_xattr->name_length = strlen(bp);
+      current_xattr->name_length = name_length;
       current_xattr->name = (char *)malloc(current_xattr->name_length);
       memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
 
       current_xattr->name = (char *)malloc(current_xattr->name_length);
       memcpy((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
 
@@ -438,73 +433,76 @@ static bxattr_exit_code linux_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
       /*
        * First see how long the value is for the extended attribute.
        */
       /*
        * 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) {
+      xattr_value_len = lgetea(jcr->last_fname, bp, NULL, 0);
+      switch (xattr_value_len) {
+      case -1:
          switch (errno) {
          case ENOENT:
          switch (errno) {
          case ENOENT:
+         case EFORMAT:
+         case ENOTSUP:
             retval = bxattr_exit_ok;
             retval = bxattr_exit_ok;
-            free(current_xattr->name);
-            free(current_xattr);
             goto bail_out;
          default:
             goto bail_out;
          default:
-            Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
+            Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
                   jcr->last_fname, be.bstrerror());
                   jcr->last_fname, be.bstrerror());
-            Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
+            Dmsg2(100, "lgetea error file=%s ERR=%s\n",
                   jcr->last_fname, be.bstrerror());
                   jcr->last_fname, be.bstrerror());
-            free(current_xattr->name);
-            free(current_xattr);
             goto bail_out;
          }
             goto bail_out;
          }
-      }
+         break;
+      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((caddr_t)current_xattr->value, 0, xattr_value_len);
 
 
-      /*
-       * Allocate space for storing the value.
-       */
-      current_xattr->value = (char *)malloc(xattr_value_len);
-      memset((caddr_t)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) {
+            switch (errno) {
+            case ENOENT:
+            case EFORMAT:
+            case ENOTSUP:
+               retval = bxattr_exit_ok;
+               goto bail_out;
+            default:
+               Mmsg2(jcr->errmsg, _("lgetea error on file \"%s\": ERR=%s\n"),
+                     jcr->last_fname, be.bstrerror());
+               Dmsg2(100, "lgetea error file=%s ERR=%s\n",
+                     jcr->last_fname, be.bstrerror());
+               goto bail_out;
+            }
+         }
+         /*
+          * Store the actual length of the value.
+          */
+         current_xattr->value_length = xattr_value_len;
+         expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
 
 
-      xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
-      if (xattr_value_len < 0) {
-         switch (errno) {
-         case ENOENT:
-            retval = bxattr_exit_ok;
-            free(current_xattr->value);
-            free(current_xattr->name);
-            free(current_xattr);
-            goto bail_out;
-         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(current_xattr->value);
-            free(current_xattr->name);
-            free(current_xattr);
+         /*
+          * Protect ourself against things getting out of hand.
+          */
+         if (expected_serialize_len >= MAX_XATTR_STREAM) {
+            Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
+                  jcr->last_fname, MAX_XATTR_STREAM);
             goto bail_out;
          }
       }
 
             goto bail_out;
          }
       }
 
-      /*
-       * Store the actual length of the value.
-       */
-      current_xattr->value_length = xattr_value_len;
-      expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
-
-      /*
-       * Protect ourself against things getting out of hand.
-       */
-      if (expected_serialize_len >= MAX_XATTR_STREAM) {
-         Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
-               jcr->last_fname, MAX_XATTR_STREAM);
-         free(current_xattr->value);
-         free(current_xattr->name);
-         free(current_xattr);
-         goto bail_out;
+      if (xattr_value_list == NULL) {
+         xattr_value_list = New(alist(10, not_owned_by_alist));
       }
 
       xattr_value_list->append(current_xattr);
       }
 
       xattr_value_list->append(current_xattr);
+      current_xattr = NULL;
       xattr_count++;
       bp = strchr(bp, '\0') + 1;
       xattr_count++;
       bp = strchr(bp, '\0') + 1;
+      break;
    }
 
    free(xattr_list);
    }
 
    free(xattr_list);
@@ -525,19 +523,24 @@ static bxattr_exit_code linux_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
          goto bail_out;
       }
 
          goto bail_out;
       }
 
-      xattr_drop_internal_table(xattr_value_list);
-
       /*
        * Send the datastream to the SD.
        */
       /*
        * Send the datastream to the SD.
        */
-      return send_xattr_stream(jcr, os_default_xattr_streams[0]);
+      retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
    } else {
    } else {
-      xattr_drop_internal_table(xattr_value_list);
-
-      return bxattr_exit_ok;
+      retval = bxattr_exit_ok;
    }
 
 bail_out:
    }
 
 bail_out:
+   if (current_xattr != NULL) {
+      if (current_xattr->value != NULL) {
+         free(current_xattr->value);
+      }
+      if (current_xattr->name != NULL) {
+         free(current_xattr->name);
+      }
+      free(current_xattr);
+   }
    if (xattr_list != NULL) {
       free(xattr_list);
    }
    if (xattr_list != NULL) {
       free(xattr_list);
    }
@@ -547,7 +550,7 @@ bail_out:
    return retval;
 }
 
    return retval;
 }
 
-static bxattr_exit_code linux_xattr_parse_streams(JCR *jcr, int stream)
+static bxattr_exit_code aix_xattr_parse_streams(JCR *jcr, int stream)
 {
    xattr_t *current_xattr;
    alist *xattr_value_list;
 {
    xattr_t *current_xattr;
    alist *xattr_value_list;
@@ -561,14 +564,16 @@ static bxattr_exit_code linux_xattr_parse_streams(JCR *jcr, int stream)
    }
 
    foreach_alist(current_xattr, xattr_value_list) {
    }
 
    foreach_alist(current_xattr, xattr_value_list) {
-      if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
+      if (lsetea(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
          switch (errno) {
          case ENOENT:
          switch (errno) {
          case ENOENT:
+         case EFORMAT:
+         case ENOTSUP:
             goto bail_out;
          default:
             goto bail_out;
          default:
-            Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
+            Mmsg2(jcr->errmsg, _("lsetea error on file \"%s\": ERR=%s\n"),
                   jcr->last_fname, be.bstrerror());
                   jcr->last_fname, be.bstrerror());
-            Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
+            Dmsg2(100, "lsetea error file=%s ERR=%s\n",
                   jcr->last_fname, be.bstrerror());
             goto bail_out;
          }
                   jcr->last_fname, be.bstrerror());
             goto bail_out;
          }
@@ -586,79 +591,706 @@ bail_out:
 /*
  * Function pointers to the build and parse function to use for these xattrs.
  */
 /*
  * Function pointers to the build and parse function to use for these xattrs.
  */
-static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = linux_xattr_build_streams;
-static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = linux_xattr_parse_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
+static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_xattr_build_streams;
+static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = aix_xattr_parse_streams;
 
 
-#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
+#elif defined(HAVE_IRIX_OS)
 
 
-#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[2] = { "system.posix1e.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 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 };
+/*
+ * 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 };
 static const char *xattr_acl_skiplist[1] = { NULL };
 static const char *xattr_skiplist[1] = { NULL };
-#endif
 
 
-static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
+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_exit_code irix_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
 {
-   bool skip_xattr;
-   char *xattr_list;
-   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[BUFSIZ], current_attrtuple[BUFSIZ];
-   xattr_t *current_xattr;
+   int cnt, xattr_count = 0;
+   attrlist_cursor_t cursor;
+   attrlist_t *attrlist;
+   attrlist_ent_t *attrlist_ent;
+   xattr_t *current_xattr = NULL;
    alist *xattr_value_list = NULL;
    alist *xattr_value_list = NULL;
+   uint32_t expected_serialize_len = 0;
    bxattr_exit_code retval = bxattr_exit_error;
    bxattr_exit_code retval = bxattr_exit_error;
+   POOLMEM *xattrbuf = get_memory(ATTR_MAX_VALUELEN);
    berrno be;
 
    berrno be;
 
-   xattr_value_list = New(alist(10, not_owned_by_alist));
+   for (cnt = 0; xattr_naming_spaces[cnt].name != NULL; cnt++) {
+      memset(cursor, 0, sizeof(attrlist_cursor_t));
+      while (1) {
+         if (attr_list(jcr->last_fname, xattrbuf, ATTR_MAX_VALUELEN,
+                       xattr_naming_spaces[cnt].flags, &cursor) != 0) {
+            switch (errno) {
+            case ENOENT:
+               retval = bxattr_exit_ok;
+               goto bail_out;
+            default:
+               Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
+                     jcr->last_fname, be.bstrerror());
+               Dmsg2(100, "attr_list error file=%s ERR=%s\n",
+                     jcr->last_fname, be.bstrerror());
+               goto bail_out;
+            }
+         }
 
 
-   /*
-    * Loop over all available xattr namespaces.
+         attrlist = (attrlist_t *)xattrbuf;
+
+         /*
+          * Walk the available attributes.
+          */
+         for (cnt = 0; cnt < attrlist->al_count; cnt++) {
+            attrlist_ent = ATTR_ENTRY(xattrbuf, cnt);
+
+            /*
+             * Each xattr valuepair starts with a magic so we can parse it easier.
+             */
+            current_xattr = (xattr_t *)malloc(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 = attrlist_ent->a_valuelen;
+            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,
+                         current_xattr->value_length, xattr_naming_spaces[cnt].flags) != 0) {
+               switch (errno) {
+               case ENOENT:
+               case ENOATTR:
+                  retval = bxattr_exit_ok;
+                  goto bail_out;
+               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.
+                   */
+                  free(current_xattr->value);
+                  current_xattr->value = (char *)malloc(current_xattr->value_length);
+                  if (attr_get(jcr->last_fname, attrlist_ent->a_name, current_xattr->value,
+                               current_xattr->value_length, xattr_naming_spaces[cnt].flags) != 0) {
+                     switch (errno) {
+                     case ENOENT:
+                     case ENOATTR:
+                        retval = bxattr_exit_ok;
+                        goto bail_out;
+                     default:
+                        Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
+                              jcr->last_fname, be.bstrerror());
+                        Dmsg2(100, "attr_list error file=%s ERR=%s\n",
+                              jcr->last_fname, be.bstrerror());
+                        goto bail_out;
+                     }
+                  }
+                  break;
+               default:
+                  Mmsg2(jcr->errmsg, _("attr_list error on file \"%s\": ERR=%s\n"),
+                        jcr->last_fname, be.bstrerror());
+                  Dmsg2(100, "attr_list error file=%s ERR=%s\n",
+                        jcr->last_fname, be.bstrerror());
+                  goto bail_out;
+               }
+            }
+
+            expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
+
+            /*
+             * Protect ourself against things getting out of hand.
+             */
+            if (expected_serialize_len >= MAX_XATTR_STREAM) {
+               Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
+                     jcr->last_fname, MAX_XATTR_STREAM);
+               goto bail_out;
+            }
+
+            if (xattr_value_list == NULL) {
+               xattr_value_list = New(alist(10, not_owned_by_alist));
+            }
+
+            xattr_value_list->append(current_xattr);
+            current_xattr = NULL;
+            xattr_count++;
+         }
+
+         /*
+          * 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 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, "Failed to serialize extended attributes on file \"%s\"\n",
+               jcr->last_fname);
+         goto bail_out;
+      }
+
+      /*
+       * Send the datastream to the SD.
+       */
+      retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
+   } else {
+      retval = bxattr_exit_ok;
+   }
+
+bail_out:
+   if (current_xattr != NULL) {
+      if (current_xattr->value != NULL) {
+         free(current_xattr->value);
+      }
+      if (current_xattr->name != NULL) {
+         free(current_xattr->name);
+      }
+      free(current_xattr);
+   }
+   free_pool_memory(xattrbuf);
+
+   if (xattr_value_list != NULL) {
+      xattr_drop_internal_table(xattr_value_list);
+   }
+   return retval;
+}
+
+static bxattr_exit_code irix_xattr_parse_streams(JCR *jcr, int stream)
+{
+   char *bp;
+   int cnt, cmp_size, name_space_index;
+   xattr_t *current_xattr;
+   alist *xattr_value_list;
+   berrno be;
+
+   xattr_value_list = New(alist(10, not_owned_by_alist));
+
+   if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
+      xattr_drop_internal_table(xattr_value_list);
+      return bxattr_exit_error;
+   }
+
+   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 illegal xattr named %s on file \"%s\"\n"),
+               current_xattr->name, jcr->last_fname);
+         Dmsg2(100, "Received illegal xattr named %s on file \"%s\"\n",
+               current_xattr->name, jcr->last_fname);
+         goto bail_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_len, flags) != 0) {
+         switch (errno) {
+         case ENOENT:
+            retval = bxattr_exit_ok;
+            goto bail_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_len, flags) != 0) {
+               switch (errno) {
+               case ENOENT:
+                  retval = bxattr_exit_ok;
+                  goto bail_out;
+               default:
+                  Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
+                        jcr->last_fname, be.bstrerror());
+                  Dmsg2(100, "attr_set error file=%s ERR=%s\n",
+                        jcr->last_fname, be.bstrerror());
+                  goto bail_out;
+               }
+            }
+            break;
+         default:
+            Mmsg2(jcr->errmsg, _("attr_set error on file \"%s\": ERR=%s\n"),
+                  jcr->last_fname, be.bstrerror());
+            Dmsg2(100, "attr_set error file=%s ERR=%s\n",
+                  jcr->last_fname, be.bstrerror());
+            goto bail_out;
+         }
+      }
+   }
+
+   xattr_drop_internal_table(xattr_value_list);
+   return bxattr_exit_ok;
+
+bail_out:
+   xattr_drop_internal_table(xattr_value_list);
+   return bxattr_exit_error;
+}
+
+/*
+ * Function pointers to the build and parse function to use for these xattrs.
+ */
+static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = irix_xattr_build_streams;
+static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = irix_xattr_parse_streams;
+
+#elif defined(HAVE_DARWIN_OS) || \
+      defined(HAVE_LINUX_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[2] = { "system.posix_acl_access", 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_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
+{
+   bool skip_xattr;
+   char *xattr_list, *bp;
+   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 = NULL;
+   alist *xattr_value_list = NULL;
+   bxattr_exit_code retval = bxattr_exit_error;
+   berrno be;
+
+   /*
+    * 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:
+      switch (errno) {
+      case ENOENT:
+      case ENOTSUP:
+         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 bxattr_exit_error;
+      }
+      break;
+   case 0:
+      return bxattr_exit_ok;
+   default:
+      break;
+   }
+
+   /*
+    * Allocate room for the extented attribute list.
+    */
+   xattr_list = (char *)malloc(xattr_list_len + 1);
+   memset((caddr_t)xattr_list, 0, xattr_list_len + 1);
+
+   /*
+    * Get the actual list of extended attributes names for a file.
+    */
+   xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
+   switch (xattr_list_len) {
+   case -1:
+      switch (errno) {
+      case ENOENT:
+      case ENOTSUP:
+         retval = bxattr_exit_ok;
+         goto bail_out;
+      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());
+         goto bail_out;
+      }
+      break;
+   default:
+      break;
+   }
+   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.
+    */
+   bp = xattr_list;
+   while ((bp - xattr_list) + 1 < xattr_list_len) {
+      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);
+         bp = strchr(bp, '\0') + 1;
+         continue;
+      }
+
+      /*
+       * Each xattr valuepair starts with a magic so we can parse it easier.
+       */
+      current_xattr = (xattr_t *)malloc(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((caddr_t)current_xattr->name, (caddr_t)bp, current_xattr->name_length);
+
+      expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
+
+      /*
+       * First see how long the value is for the extended attribute.
+       */
+      xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
+      switch (xattr_value_len) {
+      case -1:
+         switch (errno) {
+         case ENOENT:
+         case ENOTSUP:
+            retval = bxattr_exit_ok;
+            goto bail_out;
+         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());
+            goto bail_out;
+         }
+         break;
+      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((caddr_t)current_xattr->value, 0, xattr_value_len);
+
+         xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
+         if (xattr_value_len < 0) {
+            switch (errno) {
+            case ENOENT:
+            case ENOTSUP:
+               retval = bxattr_exit_ok;
+               goto bail_out;
+            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());
+               goto bail_out;
+            }
+         }
+         /*
+          * Store the actual length of the value.
+          */
+         current_xattr->value_length = xattr_value_len;
+         expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
+
+         /*
+          * Protect ourself against things getting out of hand.
+          */
+         if (expected_serialize_len >= MAX_XATTR_STREAM) {
+            Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
+                  jcr->last_fname, MAX_XATTR_STREAM);
+            goto bail_out;
+         }
+      }
+
+      if (xattr_value_list == NULL) {
+         xattr_value_list = New(alist(10, not_owned_by_alist));
+      }
+
+      xattr_value_list->append(current_xattr);
+      current_xattr = NULL;
+      xattr_count++;
+      bp = strchr(bp, '\0') + 1;
+      break;
+   }
+
+   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, "Failed to serialize extended attributes on file \"%s\"\n",
+               jcr->last_fname);
+         goto bail_out;
+      }
+
+      /*
+       * Send the datastream to the SD.
+       */
+      retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
+   } else {
+      retval = bxattr_exit_ok;
+   }
+
+bail_out:
+   if (current_xattr != NULL) {
+      if (current_xattr->value != NULL) {
+         free(current_xattr->value);
+      }
+      if (current_xattr->name != NULL) {
+         free(current_xattr->name);
+      }
+      free(current_xattr);
+   }
+   if (xattr_list != NULL) {
+      free(xattr_list);
+   }
+   if (xattr_value_list != NULL) {
+      xattr_drop_internal_table(xattr_value_list);
+   }
+   return retval;
+}
+
+static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
+{
+   xattr_t *current_xattr;
+   alist *xattr_value_list;
+   berrno be;
+
+   xattr_value_list = New(alist(10, not_owned_by_alist));
+
+   if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
+      xattr_drop_internal_table(xattr_value_list);
+      return bxattr_exit_error;
+   }
+
+   foreach_alist(current_xattr, xattr_value_list) {
+      if (lsetxattr(jcr->last_fname, current_xattr->name, current_xattr->value, current_xattr->value_length, 0) != 0) {
+         switch (errno) {
+         case ENOENT:
+         case ENOTSUP:
+            goto bail_out;
+         default:
+            Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
+                  jcr->last_fname, be.bstrerror());
+            Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
+                  jcr->last_fname, be.bstrerror());
+            goto bail_out;
+         }
+      }
+   }
+
+   xattr_drop_internal_table(xattr_value_list);
+   return bxattr_exit_ok;
+
+bail_out:
+   xattr_drop_internal_table(xattr_value_list);
+   return bxattr_exit_error;
+}
+
+/*
+ * Function pointers to the build and parse function to use for these xattrs.
+ */
+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_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[2] = { "system.posix1e.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 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_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
+{
+   bool skip_xattr;
+   char *xattr_list;
+   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 = NULL;
+   alist *xattr_value_list = NULL;
+   bxattr_exit_code retval = bxattr_exit_error;
+   berrno be;
+
+   /*
+    * 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];
     */
    for (namespace_index = 0; namespace_index < sizeof(os_default_xattr_namespaces) / sizeof(int); namespace_index++) {
       attrnamespace = os_default_xattr_namespaces[namespace_index];
@@ -683,7 +1315,8 @@ static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
        * they've decided to return EOPNOTSUPP instead.
        */
       xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
        * they've decided to return EOPNOTSUPP instead.
        */
       xattr_list_len = extattr_list_link(jcr->last_fname, attrnamespace, NULL, 0);
-      if (xattr_list_len < 0) {
+      switch (xattr_list_len) {
+      case -1:
          switch (errno) {
          case ENOENT:
             retval = bxattr_exit_ok;
          switch (errno) {
          case ENOENT:
             retval = bxattr_exit_ok;
@@ -707,8 +1340,11 @@ static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
                   jcr->last_fname, be.bstrerror());
             goto bail_out;
          }
                   jcr->last_fname, be.bstrerror());
             goto bail_out;
          }
-      } else if (xattr_list_len == 0) {
+         break;
+      case 0:
          continue;
          continue;
+      default:
+         break;
       }
 
       /*
       }
 
       /*
@@ -721,7 +1357,8 @@ static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
        * 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);
        * 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) {
+      switch (xattr_list_len) {
+      case -1:
          switch (errno) {
          case ENOENT:
             retval = bxattr_exit_ok;
          switch (errno) {
          case ENOENT:
             retval = bxattr_exit_ok;
@@ -733,6 +1370,9 @@ static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
                   jcr->last_fname, be.bstrerror());
             goto bail_out;
          }
                   jcr->last_fname, be.bstrerror());
             goto bail_out;
          }
+         break;
+      default:
+         break;
       }
       xattr_list[xattr_list_len] = '\0';
 
       }
       xattr_list[xattr_list_len] = '\0';
 
@@ -747,7 +1387,10 @@ static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
           * 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.
           */
           * 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 = MIN((sizeof(current_attrname) - 1), xattr_list[index]);
+         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';
 
          strncpy(current_attrname, xattr_list + (index + 1), cnt);
          current_attrname[cnt] = '\0';
 
@@ -774,7 +1417,7 @@ static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
          /*
           * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
           */
          /*
           * On some OSes we want to skip certain xattrs which are in the xattr_skiplist array.
           */
-         if (skip_xattr) {
+         if (!skip_xattr) {
             for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
                if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
                   skip_xattr = true;
             for (cnt = 0; xattr_skiplist[cnt] != NULL; cnt++) {
                if (bstrcmp(current_attrtuple, xattr_skiplist[cnt])) {
                   skip_xattr = true;
@@ -784,6 +1427,7 @@ static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
          }
 
          if (skip_xattr) {
          }
 
          if (skip_xattr) {
+            Dmsg1(100, "Skipping xattr named %s\n", current_attrname);
             continue;
          }
 
             continue;
          }
 
@@ -803,74 +1447,74 @@ static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
 
          expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
 
 
          expected_serialize_len += sizeof(current_xattr->name_length) + current_xattr->name_length;
 
-         /*
-          * First see how long the value is for the extended attribute.
-          */
-         xattr_value_len = extattr_get_link(jcr->last_fname, attrnamespace, current_attrname, NULL, 0);
-         if (xattr_value_len < 0) {
-            switch (errno) {
-            case ENOENT:
-               retval = bxattr_exit_ok;
-               free(current_xattr->name);
-               free(current_xattr);
-               goto bail_out;
-            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(current_xattr->name);
-               free(current_xattr);
-               goto bail_out;
-            }
-         }
-
-         /*
-          * Allocate space for storing the value.
-          */
-         current_xattr->value = (char *)malloc(xattr_value_len);
-         memset((caddr_t)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) {
+         /*
+          * 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:
             switch (errno) {
             case ENOENT:
                retval = bxattr_exit_ok;
             switch (errno) {
             case ENOENT:
                retval = bxattr_exit_ok;
-               free(current_xattr->value);
-               free(current_xattr->name);
-               free(current_xattr);
                goto bail_out;
             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());
                goto bail_out;
             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(current_xattr->value);
-               free(current_xattr->name);
-               free(current_xattr);
                goto bail_out;
             }
                goto bail_out;
             }
-         }
+            break;
+         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((caddr_t)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) {
+               switch (errno) {
+               case ENOENT:
+                  retval = bxattr_exit_ok;
+                  goto bail_out;
+               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());
+                  goto bail_out;
+               }
+            }
 
 
-         /*
-          * Store the actual length of the value.
-          */
-         current_xattr->value_length = xattr_value_len;
-         expected_serialize_len += sizeof(current_xattr->value_length) + current_xattr->value_length;
+            /*
+             * 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;
 
 
-         /*
-          * Protect ourself against things getting out of hand.
-          */
-         if (expected_serialize_len >= MAX_XATTR_STREAM) {
-            Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
-                  jcr->last_fname, MAX_XATTR_STREAM);
-            free(current_xattr->value);
-            free(current_xattr->name);
-            free(current_xattr);
-            goto bail_out;
+            /*
+             * Protect ourself against things getting out of hand.
+             */
+            if (expected_serialize_len >= MAX_XATTR_STREAM) {
+               Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
+                     jcr->last_fname, MAX_XATTR_STREAM);
+               goto bail_out;
+            }
+            break;
+         }
+
+         if (xattr_value_list == NULL) {
+            xattr_value_list = New(alist(10, not_owned_by_alist));
          }
 
          xattr_value_list->append(current_xattr);
          }
 
          xattr_value_list->append(current_xattr);
+         current_xattr = NULL;
          xattr_count++;
 
       }
          xattr_count++;
 
       }
@@ -903,31 +1547,32 @@ static bxattr_exit_code bsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
          goto bail_out;
       }
 
          goto bail_out;
       }
 
-      xattr_drop_internal_table(xattr_value_list);
-      xattr_value_list = NULL;
-
       /*
        * Send the datastream to the SD.
        */
       /*
        * Send the datastream to the SD.
        */
-      return send_xattr_stream(jcr, os_default_xattr_streams[0]);
+      retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
    } else {
    } else {
-      xattr_drop_internal_table(xattr_value_list);
-      xattr_value_list = NULL;
-
-      return bxattr_exit_ok;
+      retval = bxattr_exit_ok;
    }
 
 bail_out:
    if (current_attrnamespace != NULL) {
       actuallyfree(current_attrnamespace);
    }
 
 bail_out:
    if (current_attrnamespace != NULL) {
       actuallyfree(current_attrnamespace);
-      current_attrnamespace = NULL;
+   }
+   if (current_xattr != NULL) {
+      if (current_xattr->value != NULL) {
+         free(current_xattr->value);
+      }
+      if (current_xattr->name != NULL) {
+         free(current_xattr->name);
+      }
+      free(current_xattr);
    }
    if (xattr_list != NULL) {
       free(xattr_list);
    }
    if (xattr_value_list != NULL) {
       xattr_drop_internal_table(xattr_value_list);
    }
    if (xattr_list != NULL) {
       free(xattr_list);
    }
    if (xattr_value_list != NULL) {
       xattr_drop_internal_table(xattr_value_list);
-      xattr_value_list = NULL;
    }
    return retval;
 }
    }
    return retval;
 }
@@ -978,7 +1623,7 @@ static bxattr_exit_code bsd_parse_xattr_streams(JCR *jcr, int stream)
        */
       cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
                              attrname, current_xattr->value, current_xattr->value_length);
        */
       cnt = extattr_set_link(jcr->last_fname, current_attrnamespace,
                              attrname, current_xattr->value, current_xattr->value_length);
-      if (cnt < 0 || cnt != current_xattr->value_length) {
+      if (cnt < 0 || cnt != (int)current_xattr->value_length) {
          switch (errno) {
          case ENOENT:
             goto bail_out;
          switch (errno) {
          case ENOENT:
             goto bail_out;
@@ -1008,6 +1653,324 @@ bail_out:
 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_xattr_streams;
 
 static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = bsd_build_xattr_streams;
 static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = bsd_parse_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_exit_code tru64_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
+{
+   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 = NULL;
+   alist *xattr_value_list = NULL;
+   struct proplistname_args prop_args;
+   bxattr_exit_code retval = bxattr_exit_error;
+   POOLMEM *xattrbuf = get_pool_memory(PM_MESSAGE);
+   berrno be;
+
+   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:
+      switch (errno) {
+      case EOPNOTSUPP:
+         retval = bacl_exit_ok;
+         goto bail_out;
+      default:
+         Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg2(100, "getproplist error file=%s ERR=%s\n",
+               jcr->last_fname, be.bstrerror());
+         goto bail_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:
+            switch (errno) {
+            case EOPNOTSUPP:
+               retval = bacl_exit_ok;
+               goto bail_out;
+            default:
+               Mmsg2(jcr->errmsg, _("getproplist error on file \"%s\": ERR=%s\n"),
+                     jcr->last_fname, be.bstrerror());
+               Dmsg2(100, "getproplist error file=%s ERR=%s\n",
+                     jcr->last_fname, be.bstrerror());
+               goto bail_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 = bacl_exit_ok;
+            goto bail_out;
+         default:
+            break;
+         }
+      } else {
+         /**
+          * No xattr on file.
+          */
+         retval = bacl_exit_ok;
+         goto bail_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 parse it easier.
+       */
+      current_xattr = (xattr_t *)malloc(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;
+
+      /*
+       * Protect ourself against things getting out of hand.
+       */
+      if (expected_serialize_len >= MAX_XATTR_STREAM) {
+         Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
+               jcr->last_fname, MAX_XATTR_STREAM);
+         goto bail_out;
+      }
+
+      if (xattr_value_list == NULL) {
+         xattr_value_list = New(alist(10, not_owned_by_alist));
+      }
+
+      xattr_value_list->append(current_xattr);
+      current_xattr = NULL;
+      xattr_count++;
+   }
+
+   /*
+    * 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, "Failed to serialize extended attributes on file \"%s\"\n",
+               jcr->last_fname);
+         goto bail_out;
+      }
+
+      /*
+       * Send the datastream to the SD.
+       */
+      retval = send_xattr_stream(jcr, os_default_xattr_streams[0]);
+   }
+
+bail_out:
+   if (current_xattr != NULL) {
+      if (current_xattr->value != NULL) {
+         free(current_xattr->value);
+      }
+      if (current_xattr->name != NULL) {
+         free(current_xattr->name);
+      }
+      free(current_xattr);
+   }
+   if (xattr_value_list != NULL) {
+      xattr_drop_internal_table(xattr_value_list);
+   }
+   free_pool_memory(xattrbuf);
+
+   return retval;
+}
+
+static bxattr_exit_code tru64_parse_xattr_streams(JCR *jcr, int stream)
+{
+   char *bp, *xattrbuf = NULL;
+   int32_t xattrbuf_size, cnt;
+   xattr_t *current_xattr;
+   alist *xattr_value_list;
+   berrno be;
+
+   xattr_value_list = New(alist(10, not_owned_by_alist));
+
+   if (unserialize_xattr_stream(jcr, xattr_value_list) != bxattr_exit_ok) {
+      xattr_drop_internal_table(xattr_value_list);
+      return bxattr_exit_error;
+   }
+
+   /*
+    * 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, "Unable create proper proplist to restore xattrs on file \"%s\"\n",
+            jcr->last_fname);
+      goto bail_out;
+   }
+
+   /*
+    * Restore the list of extended attributes on the file.
+    */
+   cnt = setproplist(jcr->last_fname, 1, xattrbuf_size, xattrbuf);
+   switch (cnt) {
+   case -1:
+      switch (errno) {
+      case EOPNOTSUPP:
+         retval = bacl_exit_ok;
+         goto bail_out;
+      default:
+         Mmsg2(jcr->errmsg, _("setproplist error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg2(100, "setproplist error file=%s ERR=%s\n",
+               jcr->last_fname, be.bstrerror());
+         goto bail_out;
+      }
+      break;
+   default:
+      break;
+   }
+
+   free(xattrbuf);
+
+   xattr_drop_internal_table(xattr_value_list);
+   return bxattr_exit_ok;
+
+bail_out:
+   if (xattrbuf) {
+      free(xattrbuf);
+   }
+   xattr_drop_internal_table(xattr_value_list);
+   return bxattr_exit_error;
+}
+
+/*
+ * Function pointers to the build and parse function to use for these xattrs.
+ */
+static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_xattr_streams;
+static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = tru64_parse_xattr_streams;
+
 #elif defined(HAVE_SUN_OS)
 /*
  * Solaris extended attributes were introduced in Solaris 9
 #elif defined(HAVE_SUN_OS)
 /*
  * Solaris extended attributes were introduced in Solaris 9
@@ -1382,7 +2345,7 @@ static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_n
    char link_source[PATH_MAX];
    char *acl_text = NULL;
    char attribs[MAXSTRING];
    char link_source[PATH_MAX];
    char *acl_text = NULL;
    char attribs[MAXSTRING];
-   char buffer[BUFSIZ];
+   char buffer[XATTR_BUFSIZ];
    bxattr_exit_code retval = bxattr_exit_error;
    berrno be;
 
    bxattr_exit_code retval = bxattr_exit_error;
    berrno be;
 
@@ -1767,7 +2730,7 @@ static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespac
    /*
     * Walk the namespace.
     */
    /*
     * Walk the namespace.
     */
-   while (dp = readdir(dirp)) {
+   while ((dp = readdir(dirp)) != NULL) {
       /*
        * Skip only the toplevel . dir.
        */
       /*
        * Skip only the toplevel . dir.
        */