From 64708643d4dc9454faaccd720ab9b8a53b5aecf9 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Mon, 6 Oct 2014 14:26:24 -0600
Subject: libport: Add support for FreeBSD style extended attributes.

---
 configure.ac      |  2 +-
 libs/port/xattr.c | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index 68dca0a..3b0da05 100644
--- a/configure.ac
+++ b/configure.ac
@@ -670,7 +670,7 @@ AC_CHECK_HEADERS([libprocstat.h],,,
 
 if test "x$with_xattr" != "xno"
 then
-    AC_CHECK_HEADERS(attr/xattr.h, [HAVE_XATTR=1])
+    AC_CHECK_HEADERS(attr/xattr.h sys/extattr.h, [HAVE_XATTR=1])
     AC_CHECK_HEADERS(sys/xattr.h, [HAVE_XATTR=1]
         [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/xattr.h>]], [[getxattr("", "", "", 0, 0, 0);]])],
             [AC_DEFINE(XATTR_ADDITIONAL_OPTIONS, 1, [Define if xattr functions take additional arguments (Mac OS X)])])])
diff --git a/libs/port/xattr.c b/libs/port/xattr.c
index efc65c5..92a717e 100644
--- a/libs/port/xattr.c
+++ b/libs/port/xattr.c
@@ -26,17 +26,40 @@
 # include <attr/xattr.h>
 #elif defined(HAVE_SYS_XATTR_H)
 # include <sys/xattr.h>
+#elif defined(HAVE_SYS_EXTATTR_H)
+# undef XATTR_ADDITIONAL_OPTIONS
+# include <sys/extattr.h>
 #endif
 
 #include <ctype.h>
 #include <errno.h>
 
+#ifndef XATTR_USER_PREFIX_LEN
+# define XATTR_USER_PREFIX_LEN (sizeof(XATTR_USER_PREFIX) - 1)
+#endif
+
+#ifdef HAVE_SYS_EXTATTR_H
+static inline int xattr_valid_namespace( const char *name )
+{
+    if (strncmp( XATTR_USER_PREFIX, name, XATTR_USER_PREFIX_LEN ) != 0)
+    {
+        errno = EPERM;
+        return 0;
+    }
+    return 1;
+}
+#endif
+
 int xattr_fget( int filedes, const char *name, void *value, size_t size )
 {
 #if defined(XATTR_ADDITIONAL_OPTIONS)
     return fgetxattr( filedes, name, value, size, 0, 0 );
 #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H)
     return fgetxattr( filedes, name, value, size );
+#elif defined(HAVE_SYS_EXTATTR_H)
+    if (!xattr_valid_namespace( name )) return -1;
+    return extattr_get_fd( filedes, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN],
+                           value, size );
 #else
     errno = ENOSYS;
     return -1;
@@ -49,6 +72,9 @@ int xattr_fremove( int filedes, const char *name )
     return fremovexattr( filedes, name, 0 );
 #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H)
     return fremovexattr( filedes, name );
+#elif defined(HAVE_SYS_EXTATTR_H)
+    if (!xattr_valid_namespace( name )) return -1;
+    return extattr_delete_fd( filedes, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN] );
 #else
     errno = ENOSYS;
     return -1;
@@ -61,6 +87,10 @@ int xattr_fset( int filedes, const char *name, void *value, size_t size )
     return fsetxattr( filedes, name, value, size, 0, 0 );
 #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H)
     return fsetxattr( filedes, name, value, size, 0 );
+#elif defined(HAVE_SYS_EXTATTR_H)
+    if (!xattr_valid_namespace( name )) return -1;
+    return extattr_set_fd( filedes, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN],
+                           value, size );
 #else
     errno = ENOSYS;
     return -1;
@@ -73,6 +103,10 @@ int xattr_get( const char *path, const char *name, void *value, size_t size )
     return getxattr( path, name, value, size, 0, 0 );
 #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H)
     return getxattr( path, name, value, size );
+#elif defined(HAVE_SYS_EXTATTR_H)
+    if (!xattr_valid_namespace( name )) return -1;
+    return extattr_get_file( path, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN],
+                             value, size );
 #else
     errno = ENOSYS;
     return -1;
@@ -85,6 +119,9 @@ int xattr_remove( const char *path, const char *name )
     return removexattr( path, name, 0 );
 #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H)
     return removexattr( path, name );
+#elif defined(HAVE_SYS_EXTATTR_H)
+    if (!xattr_valid_namespace( name )) return -1;
+    return extattr_delete_file( path, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN] );
 #else
     errno = ENOSYS;
     return -1;
@@ -97,6 +134,10 @@ int xattr_set( const char *path, const char *name, void *value, size_t size )
     return setxattr( path, name, value, size, 0, 0 );
 #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H)
     return setxattr( path, name, value, size, 0 );
+#elif defined(HAVE_SYS_EXTATTR_H)
+    if (!xattr_valid_namespace( name )) return -1;
+    return extattr_set_file( path, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN],
+                             value, size );
 #else
     errno = ENOSYS;
     return -1;
-- 
1.9.1

