]> arthur.barton.de Git - netatalk.git/commitdiff
Begin Solaris EA VFS cleanup
authorfranklahm <franklahm>
Fri, 23 Oct 2009 14:09:50 +0000 (14:09 +0000)
committerfranklahm <franklahm>
Fri, 23 Oct 2009 14:09:50 +0000 (14:09 +0000)
configure.in
libatalk/vfs/Makefile.am
libatalk/vfs/ea.c
libatalk/vfs/ea_solaris.c [new file with mode: 0644]

index a0dff97e2e57827b9958aa367f2710ea8222b62d..70b3f3e0e0167d37d079304ed27dbbef9281de09 100644 (file)
@@ -1,4 +1,4 @@
-dnl $Id: configure.in,v 1.221 2009-10-22 08:36:30 franklahm Exp $
+dnl $Id: configure.in,v 1.222 2009-10-23 14:09:50 franklahm Exp $
 dnl configure.in for netatalk
 
 AC_INIT(etc/afpd/main.c)
@@ -1047,6 +1047,7 @@ neta_cv_eas="adouble"
 if test "x$this_os" = "xsolaris"; then
        AC_CHECK_LIB(c,attropen, [
             neta_cv_eas="$neta_cv_eas Solaris"
+            neta_cv_solaris_eas="yes"
             AC_MSG_NOTICE([Enabling Solaris Extended Attributes support])
             AC_DEFINE([HAVE_SOLARIS_EAS], 1, [Enable Extended Attributes])
         ]
@@ -1068,7 +1069,7 @@ AM_CONDITIONAL(COMPILE_A2BOOT, test x$compile_a2boot = xyes)
 AM_CONDITIONAL(HAVE_LIBGCRYPT, test x$neta_cv_have_libgcrypt = xyes)
 AM_CONDITIONAL(HAVE_OPENSSL, test x$neta_cv_have_openssl = xyes)
 AM_CONDITIONAL(USE_NFSv4_ACLS, test x$neta_cv_nfsv4acl = xyes)
-AM_CONDITIONAL(USE_EXT_ATTRS, test x$neta_cv_extattrs = xyes)
+AM_CONDITIONAL(USE_SOLARIS_EAS, test x$neta_cv_solaris_eas = xyes)
 AM_CONDITIONAL(USE_DHX, test x$neta_cv_compile_dhx = xyes)
 AM_CONDITIONAL(USE_DHX2, test x$neta_cv_compile_dhx2 = xyes)
 AM_CONDITIONAL(USE_RANDNUM, test x$neta_cv_have_openssl = xyes)
index f208caf1538117628e3925962c761b3ac528d598..45c48304eeefeff570b355b7484086f7fc2fc0e9 100644 (file)
@@ -8,3 +8,6 @@ if USE_NFSv4_ACLS
 libvfs_la_SOURCES += acl.c
 endif
 
+if USE_SOLARIS_EAS
+libvfs_la_SOURCES += ea_solaris.c
+endif
index e5d4fdb8a29449041ee5a2cca4b820df453714d0..d6e7d87e08aefe8c624bc35ea4fbc52b56820ee4 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  $Id: ea.c,v 1.9 2009-10-22 12:35:39 franklahm Exp $
+  $Id: ea.c,v 1.10 2009-10-23 14:09:51 franklahm Exp $
   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
   GNU General Public License for more details.
 */
 
-/* According to man fsattr.5 we must define _ATFILE_SOURCE */
-#ifdef HAVE_SOLARIS_EAS
-#define _ATFILE_SOURCE
-#endif
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
@@ -1127,12 +1122,7 @@ exit:
  * Copies names of all EAs of uname as consecutive C strings into rbuf.
  * Increments *rbuflen accordingly.
  */
-int set_ea(const struct vol * restrict vol,
-           const char * restrict uname,
-           const char * restrict attruname,
-           const char * restrict ibuf,
-           size_t attrsize,
-           int oflag)
+int set_ea(VFS_FUNC_ARGS_EA_SET)
 {
     int ret = AFP_OK;
     struct ea ea;
@@ -1184,10 +1174,7 @@ exit:
  *
  * Removes EA attruname from file uname.
  */
-int remove_ea(const struct vol * restrict vol,
-              const char * restrict uname,
-              const char * restrict attruname,
-              int oflag)
+int remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
 {
     int ret = AFP_OK;
     struct ea ea;
@@ -1221,374 +1208,6 @@ exit:
     return ret;
 }
 
-/**********************************************************************************
- * Solaris EA VFS funcs
- **********************************************************************************/
-
-/*
- * Function: sol_get_easize
- *
- * Purpose: get size of an EA on Solaris native EA
- *
- * Arguments:
- *
- *    vol          (r) current volume
- *    rbuf         (w) DSI reply buffer
- *    rbuflen      (rw) current length of data in reply buffer
- *    uname        (r) filename
- *    oflag        (r) link and create flag
- *    attruname    (r) name of attribute
- *
- * Returns: AFP code: AFP_OK on success or appropiate AFP error code
- *
- * Effects:
- *
- * Copies EA size into rbuf in network order. Increments *rbuflen +4.
- */
-#ifdef HAVE_SOLARIS_EAS
-int sol_get_easize(const struct vol * restrict vol,
-                   char * restrict rbuf,
-                   int * restrict rbuflen,
-                   const char * restrict uname,
-                   int oflag,
-                   cons char * restrict attruname)
-{
-    int                 ret, attrdirfd;
-    uint32_t            attrsize;
-    struct stat         st;
-
-    LOG(log_debug7, logtype_afpd, "sol_getextattr_size(%s): attribute: \"%s\"", uname, attruname);
-
-    if ( -1 == (attrdirfd = attropen(uname, ".", O_RDONLY | oflag))) {
-        if (errno == ELOOP) {
-            /* its a symlink and client requested O_NOFOLLOW  */
-            LOG(log_debug, logtype_afpd, "sol_getextattr_size(%s): encountered symlink with kXAttrNoFollow", uname);
-
-            memset(rbuf, 0, 4);
-            *rbuflen += 4;
-
-            return AFP_OK;
-        }
-        LOG(log_error, logtype_afpd, "sol_getextattr_size: attropen error: %s", strerror(errno));
-        return AFPERR_MISC;
-    }
-
-    if ( -1 == (fstatat(attrdirfd, attruname, &st, 0))) {
-        LOG(log_error, logtype_afpd, "sol_getextattr_size: fstatat error: %s", strerror(errno));
-        ret = AFPERR_MISC;
-        goto exit;
-    }
-    attrsize = (st.st_size > MAX_EA_SIZE) ? MAX_EA_SIZE : st.st_size;
-
-    /* Start building reply packet */
-
-    LOG(log_debug7, logtype_afpd, "sol_getextattr_size(%s): attribute: \"%s\", size: %u", uname, attruname, attrsize);
-
-    /* length of attribute data */
-    attrsize = htonl(attrsize);
-    memcpy(rbuf, &attrsize, 4);
-    *rbuflen += 4;
-
-    ret = AFP_OK;
-
-exit:
-    close(attrdirfd);
-    return ret;
-}
-#endif /* HAVE_SOLARIS_EAS */
-
-/*
- * Function: sol_get_eacontent
- *
- * Purpose: copy Solaris native EA into rbuf
- *
- * Arguments:
- *
- *    vol          (r) current volume
- *    rbuf         (w) DSI reply buffer
- *    rbuflen      (rw) current length of data in reply buffer
- *    uname        (r) filename
- *    oflag        (r) link and create flag
- *    attruname    (r) name of attribute
- *    maxreply     (r) maximum EA size as of current specs/real-life
- *
- * Returns: AFP code: AFP_OK on success or appropiate AFP error code
- *
- * Effects:
- *
- * Copies EA into rbuf. Increments *rbuflen accordingly.
- */
-#ifdef HAVE_SOLARIS_EAS
-int sol_get_eacontent(const struct vol * restrict vol,
-                      char * restrict rbuf,
-                      int * restrict rbuflen,
-                      const char * restrict uname,
-                      int oflag,
-                      char * restrict attruname,
-                      int maxreply)
-{
-    int                 ret, attrdirfd;
-    size_t              toread, okread = 0, len;
-    char                *datalength;
-    struct stat         st;
-
-    if ( -1 == (attrdirfd = attropen(uname, attruname, O_RDONLY | oflag))) {
-        if (errno == ELOOP) {
-            /* its a symlink and client requested O_NOFOLLOW  */
-            LOG(log_debug, logtype_afpd, "sol_getextattr_content(%s): encountered symlink with kXAttrNoFollow", uname);
-
-            memset(rbuf, 0, 4);
-            *rbuflen += 4;
-
-            return AFP_OK;
-        }
-        LOG(log_error, logtype_afpd, "sol_getextattr_content(%s): attropen error: %s", attruname, strerror(errno));
-        return AFPERR_MISC;
-    }
-
-    if ( -1 == (fstat(attrdirfd, &st))) {
-        LOG(log_error, logtype_afpd, "sol_getextattr_content(%s): fstatat error: %s", attruname,strerror(errno));
-        ret = AFPERR_MISC;
-        goto exit;
-    }
-
-    /* Start building reply packet */
-
-    maxreply -= MAX_REPLY_EXTRA_BYTES;
-    if (maxreply > MAX_EA_SIZE)
-        maxreply = MAX_EA_SIZE;
-
-    /* But never send more than the client requested */
-    toread = (maxreply < st.st_size) ? maxreply : st.st_size;
-
-    LOG(log_debug7, logtype_afpd, "sol_getextattr_content(%s): attribute: \"%s\", size: %u", uname, attruname, maxreply);
-
-    /* remember where we must store length of attribute data in rbuf */
-    datalength = rbuf;
-    rbuf += 4;
-    *rbuflen += 4;
-
-    while (1) {
-        len = read(attrdirfd, rbuf, toread);
-        if (len == -1) {
-            LOG(log_error, logtype_afpd, "sol_getextattr_content(%s): read error: %s", attruname, strerror(errno));
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-        okread += len;
-        rbuf += len;
-        *rbuflen += len;
-        if ((len == 0) || (okread == toread))
-            break;
-    }
-
-    okread = htonl((uint32_t)okread);
-    memcpy(datalength, &okread, 4);
-
-    ret = AFP_OK;
-
-exit:
-    close(attrdirfd);
-    return ret;
-}
-#endif /* HAVE_SOLARIS_EAS */
-
-/*
- * Function: sol_list_eas
- *
- * Purpose: copy names of Solaris native EA into attrnamebuf
- *
- * Arguments:
- *
- *    vol          (r) current volume
- *    attrnamebuf  (w) store names a consecutive C strings here
- *    buflen       (rw) length of names in attrnamebuf
- *    uname        (r) filename
- *    oflag        (r) link and create flag
- *
- * Returns: AFP code: AFP_OK on success or appropiate AFP error code
- *
- * Effects:
- *
- * Copies names of all EAs of uname as consecutive C strings into rbuf.
- * Increments *rbuflen accordingly.
- */
-#ifdef HAVE_SOLARIS_EAS
-int sol_list_eas(const struct vol * restrict vol,
-                 char * restrict attrnamebuf,
-                 int * restrict buflen,
-                 const char * restrict uname,
-                 int oflag)
-{
-    int ret, attrbuflen = *buflen, len, attrdirfd = 0;
-    struct dirent *dp;
-    DIR *dirp = NULL;
-
-    /* Now list file attribute dir */
-    if ( -1 == (attrdirfd = attropen( uname, ".", O_RDONLY | oflag))) {
-        if (errno == ELOOP) {
-            /* its a symlink and client requested O_NOFOLLOW */
-            ret = AFPERR_BADTYPE;
-            goto exit;
-        }
-        LOG(log_error, logtype_afpd, "sol_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno));
-        ret = AFPERR_MISC;
-        goto exit;
-    }
-
-    if (NULL == (dirp = fdopendir(attrdirfd))) {
-        LOG(log_error, logtype_afpd, "sol_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno));
-        ret = AFPERR_MISC;
-        goto exit;
-    }
-
-    while ((dp = readdir(dirp)))  {
-        /* check if its "." or ".." */
-        if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0) ||
-            (strcmp(dp->d_name, "SUNWattr_ro") == 0) || (strcmp(dp->d_name, "SUNWattr_rw") == 0))
-            continue;
-
-        len = strlen(dp->d_name);
-
-        /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
-        if ( 0 >= ( len = convert_string(vol->v_volcharset, CH_UTF8_MAC, dp->d_name, len, attrnamebuf + attrbuflen, 255)) ) {
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-        if (len == 255)
-            /* convert_string didn't 0-terminate */
-            attrnamebuf[attrbuflen + 255] = 0;
-
-        LOG(log_debug7, logtype_afpd, "sol_list_extattr(%s): attribute: %s", uname, dp->d_name);
-
-        attrbuflen += len + 1;
-        if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) {
-            /* Next EA name could overflow, so bail out with error.
-               FIXME: evantually malloc/memcpy/realloc whatever.
-               Is it worth it ? */
-            LOG(log_warning, logtype_afpd, "sol_list_extattr(%s): running out of buffer for EA names", uname);
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-    }
-
-    ret = AFP_OK;
-
-exit:
-    if (dirp)
-        closedir(dirp);
-
-    if (attrdirfd > 0)
-        close(attrdirfd);
-
-    *buflen = attrbuflen;
-    return ret;
-}
-#endif /* HAVE_SOLARIS_EAS */
-
-/*
- * Function: sol_set_ea
- *
- * Purpose: set a Solaris native EA
- *
- * Arguments:
- *
- *    vol          (r) current volume
- *    uname        (r) filename
- *    attruname    (r) EA name
- *    ibuf         (r) buffer with EA content
- *    attrsize     (r) length EA in ibuf
- *    oflag        (r) link and create flag
- *
- * Returns: AFP code: AFP_OK on success or appropiate AFP error code
- *
- * Effects:
- *
- * Copies names of all EAs of uname as consecutive C strings into rbuf.
- * Increments *rbuflen accordingly.
- */
-#ifdef HAVE_SOLARIS_EAS
-int sol_set_ea(const struct vol * restrict vol,
-               const char * restrict u_name,
-               const char * restrict attruname,
-               const char * restrict ibuf,
-               size_t attrsize,
-               int oflag)
-{
-    int attrdirfd;
-
-    if ( -1 == (attrdirfd = attropen(u_name, attruname, oflag, 0666))) {
-        if (errno == ELOOP) {
-            /* its a symlink and client requested O_NOFOLLOW  */
-            LOG(log_debug, logtype_afpd, "afp_setextattr(%s): encountered symlink with kXAttrNoFollow", s_path->u_name);
-            return AFP_OK;
-        }
-        LOG(log_error, logtype_afpd, "afp_setextattr(%s): attropen error: %s", s_path->u_name, strerror(errno));
-        return AFPERR_MISC;
-    }
-
-    if ((write(attrdirfd, ibuf, attrsize)) != attrsize) {
-        LOG(log_error, logtype_afpd, "afp_setextattr(%s): read error: %s", attruname, strerror(errno));
-        return AFPERR_MISC;
-    }
-
-    return AFP_OK;
-}
-#endif /* HAVE_SOLARIS_EAS */
-
-/*
- * Function: sol_remove_ea
- *
- * Purpose: remove a Solaris native EA
- *
- * Arguments:
- *
- *    vol          (r) current volume
- *    uname        (r) filename
- *    attruname    (r) EA name
- *    oflag        (r) link and create flag
- *
- * Returns: AFP code: AFP_OK on success or appropiate AFP error code
- *
- * Effects:
- *
- * Removes EA attruname from file uname.
- */
-#ifdef HAVE_SOLARIS_EAS
-int sol_remove_ea(const struct vol * restrict vol,
-                  const char * restrict uname,
-                  const char * restrict attruname,
-                  int oflag)
-{
-    int attrdirfd;
-
-    if ( -1 == (attrdirfd = attropen(uname, ".", oflag))) {
-        switch (errno) {
-        case ELOOP:
-            /* its a symlink and client requested O_NOFOLLOW  */
-            LOG(log_debug, logtype_afpd, "afp_remextattr(%s): encountered symlink with kXAttrNoFollow", s_path->u_name);
-            return AFP_OK;
-        case EACCES:
-            LOG(log_debug, logtype_afpd, "afp_remextattr(%s): unlinkat error: %s", s_path->u_name, strerror(errno));
-            return AFPERR_ACCESS;
-        default:
-            LOG(log_error, logtype_afpd, "afp_remextattr(%s): attropen error: %s", s_path->u_name, strerror(errno));
-            return AFPERR_MISC;
-        }
-    }
-
-    if ( -1 == (unlinkat(attrdirfd, attruname, 0)) ) {
-        if (errno == EACCES) {
-            LOG(log_debug, logtype_afpd, "afp_remextattr(%s): unlinkat error: %s", s_path->u_name, strerror(errno));
-            return AFPERR_ACCESS;
-        }
-        LOG(log_error, logtype_afpd, "afp_remextattr(%s): unlinkat error: %s", s_path->u_name, strerror(errno));
-        return AFPERR_MISC;
-    }
-
-}
-#endif /* HAVE_SOLARIS_EAS */
-
 /******************************************************************************************
  * EA VFS funcs that deal with file/dir cp/mv/rm
  ******************************************************************************************/
diff --git a/libatalk/vfs/ea_solaris.c b/libatalk/vfs/ea_solaris.c
new file mode 100644 (file)
index 0000000..0752dbb
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+  $Id: ea_solaris.c,v 1.1 2009-10-23 14:09:51 franklahm Exp $
+  Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+*/
+
+/* According to man fsattr.5 we must define _ATFILE_SOURCE */
+#define _ATFILE_SOURCE
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <stdint.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <atalk/adouble.h>
+#include <atalk/ea.h>
+#include <atalk/afp.h>
+#include <atalk/logger.h>
+#include <atalk/volume.h>
+#include <atalk/vfs.h>
+#include <atalk/util.h>
+#include <atalk/unix.h>
+
+
+/**********************************************************************************
+ * Solaris EA VFS funcs
+ **********************************************************************************/
+
+/*
+ * Function: sol_get_easize
+ *
+ * Purpose: get size of an EA on Solaris native EA
+ *
+ * Arguments:
+ *
+ *    vol          (r) current volume
+ *    rbuf         (w) DSI reply buffer
+ *    rbuflen      (rw) current length of data in reply buffer
+ *    uname        (r) filename
+ *    oflag        (r) link and create flag
+ *    attruname    (r) name of attribute
+ *
+ * Returns: AFP code: AFP_OK on success or appropiate AFP error code
+ *
+ * Effects:
+ *
+ * Copies EA size into rbuf in network order. Increments *rbuflen +4.
+ */
+int sol_get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
+{
+    int                 ret, attrdirfd;
+    uint32_t            attrsize;
+    struct stat         st;
+
+    LOG(log_debug7, logtype_afpd, "sol_getextattr_size(%s): attribute: \"%s\"", uname, attruname);
+
+    if ( -1 == (attrdirfd = attropen(uname, ".", O_RDONLY | oflag))) {
+        if (errno == ELOOP) {
+            /* its a symlink and client requested O_NOFOLLOW  */
+            LOG(log_debug, logtype_afpd, "sol_getextattr_size(%s): encountered symlink with kXAttrNoFollow", uname);
+
+            memset(rbuf, 0, 4);
+            *rbuflen += 4;
+
+            return AFP_OK;
+        }
+        LOG(log_error, logtype_afpd, "sol_getextattr_size: attropen error: %s", strerror(errno));
+        return AFPERR_MISC;
+    }
+
+    if ( -1 == (fstatat(attrdirfd, attruname, &st, 0))) {
+        LOG(log_error, logtype_afpd, "sol_getextattr_size: fstatat error: %s", strerror(errno));
+        ret = AFPERR_MISC;
+        goto exit;
+    }
+    attrsize = (st.st_size > MAX_EA_SIZE) ? MAX_EA_SIZE : st.st_size;
+
+    /* Start building reply packet */
+
+    LOG(log_debug7, logtype_afpd, "sol_getextattr_size(%s): attribute: \"%s\", size: %u", uname, attruname, attrsize);
+
+    /* length of attribute data */
+    attrsize = htonl(attrsize);
+    memcpy(rbuf, &attrsize, 4);
+    *rbuflen += 4;
+
+    ret = AFP_OK;
+
+exit:
+    close(attrdirfd);
+    return ret;
+}
+
+/*
+ * Function: sol_get_eacontent
+ *
+ * Purpose: copy Solaris native EA into rbuf
+ *
+ * Arguments:
+ *
+ *    vol          (r) current volume
+ *    rbuf         (w) DSI reply buffer
+ *    rbuflen      (rw) current length of data in reply buffer
+ *    uname        (r) filename
+ *    oflag        (r) link and create flag
+ *    attruname    (r) name of attribute
+ *    maxreply     (r) maximum EA size as of current specs/real-life
+ *
+ * Returns: AFP code: AFP_OK on success or appropiate AFP error code
+ *
+ * Effects:
+ *
+ * Copies EA into rbuf. Increments *rbuflen accordingly.
+ */
+int sol_get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
+{
+    int                 ret, attrdirfd;
+    size_t              toread, okread = 0, len;
+    char                *datalength;
+    struct stat         st;
+
+    if ( -1 == (attrdirfd = attropen(uname, attruname, O_RDONLY | oflag))) {
+        if (errno == ELOOP) {
+            /* its a symlink and client requested O_NOFOLLOW  */
+            LOG(log_debug, logtype_afpd, "sol_getextattr_content(%s): encountered symlink with kXAttrNoFollow", uname);
+
+            memset(rbuf, 0, 4);
+            *rbuflen += 4;
+
+            return AFP_OK;
+        }
+        LOG(log_error, logtype_afpd, "sol_getextattr_content(%s): attropen error: %s", attruname, strerror(errno));
+        return AFPERR_MISC;
+    }
+
+    if ( -1 == (fstat(attrdirfd, &st))) {
+        LOG(log_error, logtype_afpd, "sol_getextattr_content(%s): fstatat error: %s", attruname,strerror(errno));
+        ret = AFPERR_MISC;
+        goto exit;
+    }
+
+    /* Start building reply packet */
+
+    maxreply -= MAX_REPLY_EXTRA_BYTES;
+    if (maxreply > MAX_EA_SIZE)
+        maxreply = MAX_EA_SIZE;
+
+    /* But never send more than the client requested */
+    toread = (maxreply < st.st_size) ? maxreply : st.st_size;
+
+    LOG(log_debug7, logtype_afpd, "sol_getextattr_content(%s): attribute: \"%s\", size: %u", uname, attruname, maxreply);
+
+    /* remember where we must store length of attribute data in rbuf */
+    datalength = rbuf;
+    rbuf += 4;
+    *rbuflen += 4;
+
+    while (1) {
+        len = read(attrdirfd, rbuf, toread);
+        if (len == -1) {
+            LOG(log_error, logtype_afpd, "sol_getextattr_content(%s): read error: %s", attruname, strerror(errno));
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+        okread += len;
+        rbuf += len;
+        *rbuflen += len;
+        if ((len == 0) || (okread == toread))
+            break;
+    }
+
+    okread = htonl((uint32_t)okread);
+    memcpy(datalength, &okread, 4);
+
+    ret = AFP_OK;
+
+exit:
+    close(attrdirfd);
+    return ret;
+}
+
+/*
+ * Function: sol_list_eas
+ *
+ * Purpose: copy names of Solaris native EA into attrnamebuf
+ *
+ * Arguments:
+ *
+ *    vol          (r) current volume
+ *    attrnamebuf  (w) store names a consecutive C strings here
+ *    buflen       (rw) length of names in attrnamebuf
+ *    uname        (r) filename
+ *    oflag        (r) link and create flag
+ *
+ * Returns: AFP code: AFP_OK on success or appropiate AFP error code
+ *
+ * Effects:
+ *
+ * Copies names of all EAs of uname as consecutive C strings into rbuf.
+ * Increments *rbuflen accordingly.
+ */
+int sol_list_eas(VFS_FUNC_ARGS_EA_LIST)
+{
+    int ret, attrbuflen = *buflen, len, attrdirfd = 0;
+    struct dirent *dp;
+    DIR *dirp = NULL;
+
+    /* Now list file attribute dir */
+    if ( -1 == (attrdirfd = attropen( uname, ".", O_RDONLY | oflag))) {
+        if (errno == ELOOP) {
+            /* its a symlink and client requested O_NOFOLLOW */
+            ret = AFPERR_BADTYPE;
+            goto exit;
+        }
+        LOG(log_error, logtype_afpd, "sol_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno));
+        ret = AFPERR_MISC;
+        goto exit;
+    }
+
+    if (NULL == (dirp = fdopendir(attrdirfd))) {
+        LOG(log_error, logtype_afpd, "sol_list_extattr(%s): error opening atttribute dir: %s", uname, strerror(errno));
+        ret = AFPERR_MISC;
+        goto exit;
+    }
+
+    while ((dp = readdir(dirp)))  {
+        /* check if its "." or ".." */
+        if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0) ||
+            (strcmp(dp->d_name, "SUNWattr_ro") == 0) || (strcmp(dp->d_name, "SUNWattr_rw") == 0))
+            continue;
+
+        len = strlen(dp->d_name);
+
+        /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
+        if ( 0 >= ( len = convert_string(vol->v_volcharset, CH_UTF8_MAC, dp->d_name, len, attrnamebuf + attrbuflen, 255)) ) {
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+        if (len == 255)
+            /* convert_string didn't 0-terminate */
+            attrnamebuf[attrbuflen + 255] = 0;
+
+        LOG(log_debug7, logtype_afpd, "sol_list_extattr(%s): attribute: %s", uname, dp->d_name);
+
+        attrbuflen += len + 1;
+        if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) {
+            /* Next EA name could overflow, so bail out with error.
+               FIXME: evantually malloc/memcpy/realloc whatever.
+               Is it worth it ? */
+            LOG(log_warning, logtype_afpd, "sol_list_extattr(%s): running out of buffer for EA names", uname);
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+    }
+
+    ret = AFP_OK;
+
+exit:
+    if (dirp)
+        closedir(dirp);
+
+    if (attrdirfd > 0)
+        close(attrdirfd);
+
+    *buflen = attrbuflen;
+    return ret;
+}
+
+/*
+ * Function: sol_set_ea
+ *
+ * Purpose: set a Solaris native EA
+ *
+ * Arguments:
+ *
+ *    vol          (r) current volume
+ *    uname        (r) filename
+ *    attruname    (r) EA name
+ *    ibuf         (r) buffer with EA content
+ *    attrsize     (r) length EA in ibuf
+ *    oflag        (r) link and create flag
+ *
+ * Returns: AFP code: AFP_OK on success or appropiate AFP error code
+ *
+ * Effects:
+ *
+ * Copies names of all EAs of uname as consecutive C strings into rbuf.
+ * Increments *rbuflen accordingly.
+ */
+int sol_set_ea(VFS_FUNC_ARGS_EA_SET)
+{
+    int attrdirfd;
+
+    if ( -1 == (attrdirfd = attropen(u_name, attruname, oflag, 0666))) {
+        if (errno == ELOOP) {
+            /* its a symlink and client requested O_NOFOLLOW  */
+            LOG(log_debug, logtype_afpd, "afp_setextattr(%s): encountered symlink with kXAttrNoFollow", s_path->u_name);
+            return AFP_OK;
+        }
+        LOG(log_error, logtype_afpd, "afp_setextattr(%s): attropen error: %s", s_path->u_name, strerror(errno));
+        return AFPERR_MISC;
+    }
+
+    if ((write(attrdirfd, ibuf, attrsize)) != attrsize) {
+        LOG(log_error, logtype_afpd, "afp_setextattr(%s): read error: %s", attruname, strerror(errno));
+        return AFPERR_MISC;
+    }
+
+    return AFP_OK;
+}
+
+/*
+ * Function: sol_remove_ea
+ *
+ * Purpose: remove a Solaris native EA
+ *
+ * Arguments:
+ *
+ *    vol          (r) current volume
+ *    uname        (r) filename
+ *    attruname    (r) EA name
+ *    oflag        (r) link and create flag
+ *
+ * Returns: AFP code: AFP_OK on success or appropiate AFP error code
+ *
+ * Effects:
+ *
+ * Removes EA attruname from file uname.
+ */
+int sol_remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
+{
+    int attrdirfd;
+
+    if ( -1 == (attrdirfd = attropen(uname, ".", oflag))) {
+        switch (errno) {
+        case ELOOP:
+            /* its a symlink and client requested O_NOFOLLOW  */
+            LOG(log_debug, logtype_afpd, "afp_remextattr(%s): encountered symlink with kXAttrNoFollow", s_path->u_name);
+            return AFP_OK;
+        case EACCES:
+            LOG(log_debug, logtype_afpd, "afp_remextattr(%s): unlinkat error: %s", s_path->u_name, strerror(errno));
+            return AFPERR_ACCESS;
+        default:
+            LOG(log_error, logtype_afpd, "afp_remextattr(%s): attropen error: %s", s_path->u_name, strerror(errno));
+            return AFPERR_MISC;
+        }
+    }
+
+    if ( -1 == (unlinkat(attrdirfd, attruname, 0)) ) {
+        if (errno == EACCES) {
+            LOG(log_debug, logtype_afpd, "afp_remextattr(%s): unlinkat error: %s", s_path->u_name, strerror(errno));
+            return AFPERR_ACCESS;
+        }
+        LOG(log_error, logtype_afpd, "afp_remextattr(%s): unlinkat error: %s", s_path->u_name, strerror(errno));
+        return AFPERR_MISC;
+    }
+
+}