Index: test/Makefile.in
===================================================================
--- test/Makefile.in	(revision 606117)
+++ test/Makefile.in	(working copy)
@@ -28,7 +28,7 @@
 	testhash.lo testargs.lo testnames.lo testuser.lo testpath.lo \
 	testenv.lo testprocmutex.lo testfnmatch.lo testatomic.lo testflock.lo \
 	testsock.lo testglobalmutex.lo teststrnatcmp.lo testfilecopy.lo \
-	testtemp.lo testlfs.lo testcond.lo
+	testtemp.lo testlfs.lo testcond.lo testxattr.lo
 
 OTHER_PROGRAMS = \
 	sendfile@EXEEXT@ \
Index: test/testxattr.c
===================================================================
--- test/testxattr.c	(revision 0)
+++ test/testxattr.c	(revision 0)
@@ -0,0 +1,243 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_file_io.h"
+#include "apr_file_xattr.h"
+#include "apr_errno.h"
+#include "apr_general.h"
+#include "testutil.h"
+
+#if APR_HAS_XATTR
+
+#define DIRNAME "data"
+#define FNAME DIRNAME "/file_xattrfile.txt"
+
+#define TESTKEY1 "testkey1"
+#define TESTVAL1 "testval1"
+#define TESTKEY2 "testkey2"
+#define TESTVAL2 "testval2"
+
+/* test solaris subfilename escaping */
+#define TESTKEYSPECIAL1 "/testkey2"
+#define TESTKEYSPECIAL2 "%testkey2"
+
+static void test_xattr_set(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    apr_file_t *filetest = NULL;
+
+    rv = apr_file_open(&filetest, FNAME, 
+                       APR_WRITE | APR_CREATE | APR_DELONCLOSE, 
+                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_set(filetest, TESTKEY1, TESTVAL1,
+			    strlen(TESTVAL1), 0, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    apr_file_close(filetest);
+}
+
+static void test_xattr_set_create(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    apr_file_t *filetest = NULL;
+
+    rv = apr_file_open(&filetest, FNAME, 
+                       APR_WRITE | APR_CREATE | APR_DELONCLOSE, 
+                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_set(filetest, TESTKEY1, TESTVAL1, strlen(TESTVAL1),
+			    APR_XATTR_CREATE, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_set(filetest, TESTKEY1, TESTVAL1, strlen(TESTVAL1),
+			    APR_XATTR_CREATE, p);
+    ABTS_INT_NEQUAL(tc, APR_SUCCESS, rv);
+
+    apr_file_close(filetest);
+}
+
+static void test_xattr_set_replace(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    apr_file_t *filetest = NULL;
+
+    rv = apr_file_open(&filetest, FNAME, 
+                       APR_WRITE | APR_CREATE | APR_DELONCLOSE, 
+                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_set(filetest, TESTKEY1, TESTVAL1, strlen(TESTVAL1),
+			    APR_XATTR_REPLACE, p);
+    ABTS_INT_NEQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_set(filetest, TESTKEY1, TESTVAL1, strlen(TESTVAL1),
+			    APR_XATTR_CREATE, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_set(filetest, TESTKEY1, TESTVAL1, strlen(TESTVAL1),
+			    APR_XATTR_REPLACE, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    apr_file_close(filetest);
+}
+
+static void test_xattr_get(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    apr_file_t *filetest = NULL;
+    apr_size_t size;
+    char *val = NULL;
+
+    rv = apr_file_open(&filetest, FNAME, 
+                       APR_WRITE | APR_CREATE | APR_DELONCLOSE, 
+                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_set(filetest, TESTKEY1, TESTVAL1,
+			    strlen(TESTVAL1), 0, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_get(filetest, TESTKEY1, (void**)&val, &size, 0, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+    ABTS_INT_EQUAL(tc, strlen(TESTVAL1), size);
+    ABTS_PTR_NOTNULL(tc, val);
+    ABTS_TRUE(tc, strncmp(TESTVAL1, val, strlen(TESTVAL1)) == 0);
+
+    apr_file_close(filetest);
+}
+
+static void test_xattr_list(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    apr_file_t *filetest = NULL;
+    apr_array_header_t *list = NULL;
+        int cmp1, cmp2;
+
+    rv = apr_file_open(&filetest, FNAME, 
+                       APR_WRITE | APR_CREATE | APR_DELONCLOSE, 
+                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_set(filetest, TESTKEY1, TESTVAL1,
+			    strlen(TESTVAL1), 0, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+    rv = apr_file_xattr_set(filetest, TESTKEY2, TESTVAL2,
+			    strlen(TESTVAL2), 0, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_list(filetest, &list, 0, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+    ABTS_PTR_NOTNULL(tc, list);
+    ABTS_INT_EQUAL(tc, 2, list->nelts);
+    cmp1 = (strcmp(APR_ARRAY_IDX(list, 0, char*), TESTKEY1) == 0) &&
+           (strcmp(APR_ARRAY_IDX(list, 1, char*), TESTKEY2) == 0);
+    cmp2 = (strcmp(APR_ARRAY_IDX(list, 0, char*), TESTKEY2) == 0) &&
+           (strcmp(APR_ARRAY_IDX(list, 1, char*), TESTKEY1) == 0);
+    ABTS_TRUE(tc, cmp1 || cmp2 );
+
+    apr_file_close(filetest);
+}
+
+static void test_xattr_remove(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    apr_file_t *filetest = NULL;
+    apr_size_t size;
+    char *val = NULL;
+
+    rv = apr_file_open(&filetest, FNAME, 
+                       APR_WRITE | APR_CREATE | APR_DELONCLOSE, 
+                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_set(filetest, TESTKEY1, TESTVAL1,
+			    strlen(TESTVAL1), 0, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_remove(filetest, TESTKEY1, 0, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_get(filetest, TESTKEY1, (void**)&val, &size, 0, p);
+    ABTS_INT_NEQUAL(tc, APR_SUCCESS, rv);
+
+    apr_file_close(filetest);
+}
+
+static void test_xattr_special_chars(abts_case *tc, void *data)
+{
+    apr_status_t rv;
+    apr_file_t *filetest = NULL;
+    apr_size_t size;
+    const char *name = (const char*)data;
+    char *val = NULL;
+    apr_array_header_t *list = NULL;
+    int cmp1, cmp2;
+
+    rv = apr_file_open(&filetest, FNAME, 
+                       APR_WRITE | APR_CREATE | APR_DELONCLOSE, 
+                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_set(filetest, name, TESTVAL1,
+			    strlen(TESTVAL1), 0, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+    rv = apr_file_xattr_get(filetest, name, (void**)&val, &size, 0, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+    ABTS_INT_EQUAL(tc, strlen(TESTVAL1), size);
+    ABTS_PTR_NOTNULL(tc, val);
+    ABTS_TRUE(tc, strncmp(TESTVAL1, val, strlen(TESTVAL1)) == 0);
+
+    rv = apr_file_xattr_list(filetest, &list, 0, p);
+    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+    ABTS_PTR_NOTNULL(tc, list);
+    ABTS_INT_EQUAL(tc, 1, list->nelts);
+    ABTS_TRUE(tc, strcmp(name, APR_ARRAY_IDX(list, 0, char*)) == 0);
+
+    apr_file_close(filetest);
+}
+
+#else
+
+static void test_xattr_not_impl(abts_case *tc, void *data)
+{
+    ABTS_NOT_IMPL(tc, "xattr not implemented on this platform");
+}
+
+#endif /* APR_HAS_XATTR */
+
+abts_suite *testxattr(abts_suite *suite)
+{
+    suite = ADD_SUITE(suite)
+
+#if !APR_HAS_XATTR
+    abts_run_test(suite, test_xattr_not_impl, NULL);
+#else
+    abts_run_test(suite, test_xattr_set, NULL);
+    abts_run_test(suite, test_xattr_set_create, NULL);
+    abts_run_test(suite, test_xattr_set_replace, NULL);
+    abts_run_test(suite, test_xattr_get, NULL);
+    abts_run_test(suite, test_xattr_list, NULL);
+    abts_run_test(suite, test_xattr_remove, NULL);
+    abts_run_test(suite, test_xattr_special_chars, TESTKEYSPECIAL1);
+    abts_run_test(suite, test_xattr_special_chars, TESTKEYSPECIAL2);
+#endif
+
+    return suite;
+}
Index: test/abts_tests.h
===================================================================
--- test/abts_tests.h	(revision 606117)
+++ test/abts_tests.h	(working copy)
@@ -66,7 +66,8 @@
     {testtime},
     {testud},
     {testuser},
-    {testvsn}
+    {testvsn},
+    {testxattr}
 };
 
 #endif /* APR_TEST_INCLUDES */
Index: test/testutil.h
===================================================================
--- test/testutil.h	(revision 606117)
+++ test/testutil.h	(working copy)
@@ -102,5 +102,6 @@
 abts_suite *testud(abts_suite *suite);
 abts_suite *testuser(abts_suite *suite);
 abts_suite *testvsn(abts_suite *suite);
+abts_suite *testxattr(abts_suite *suite);
 
 #endif /* APR_TEST_INCLUDES */

