]> arthur.barton.de Git - netatalk.git/commitdiff
Merge master
authorFrank Lahm <franklahm@googlemail.com>
Wed, 15 Dec 2010 11:47:54 +0000 (12:47 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Wed, 15 Dec 2010 11:47:54 +0000 (12:47 +0100)
32 files changed:
VERSION
bin/megatron/Makefile.am
configure.in
etc/afpd/file.c
etc/afpd/status.c
etc/afpd/uam.c
etc/afpd/unix.c
etc/afpd/volume.c
etc/uams/uams_dhx_pam.c
include/atalk/adouble.h
include/atalk/dsi.h
include/atalk/ea.h
include/atalk/util.h
libatalk/Makefile.am
libatalk/acl/unix.c
libatalk/adouble/ad_attr.c
libatalk/adouble/ad_date.c
libatalk/adouble/ad_flush.c
libatalk/adouble/ad_lock.c
libatalk/adouble/ad_open.c
libatalk/compat/rquota_xdr.c
libatalk/util/unix.c
libatalk/util/volinfo.c
libatalk/vfs/Makefile.am
libatalk/vfs/ea.c [deleted file]
libatalk/vfs/ea_ad.c [new file with mode: 0644]
libatalk/vfs/ea_sys.c
libatalk/vfs/extattr.c [new file with mode: 0644]
libatalk/vfs/sys_ea.c [deleted file]
libatalk/vfs/vfs.c
man/man1/Makefile.am
sys/netatalk/at.h

diff --git a/VERSION b/VERSION
index 5903c07d4c0d37d734b2844f6c7873e08884ac37..48898d6a616ca58a9e8798ab09639b25511eaf08 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.2alpha5
\ No newline at end of file
+3.0dev
\ No newline at end of file
index c93e201fd3fe696f371b86e0242ce286823d3f04..3032efa4bc2e09716bc7e8929326d71ca38b377b 100644 (file)
@@ -1,23 +1,4 @@
 # Makefile.am for bin/megatron/
 
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
-
-bin_PROGRAMS = megatron
-
-megatron_SOURCES = asingle.c hqx.c macbin.c megatron.c nad.c updcrc.c
-megatron_LDADD = $(top_builddir)/libatalk/libatalk.la
-
-noinst_HEADERS = asingle.h megatron.h hqx.h macbin.h nad.h updcrc.h
-
-LINKS = unbin unhex unsingle hqx2bin single2bin macbinary binheader nadheader
-
-install-exec-hook:
-       @for LINK in $(LINKS); do \
-               rm -f $(DESTDIR)$(bindir)/$$LINK; \
-               $(LN_S) megatron $(DESTDIR)$(bindir)/$$LINK; \
-       done
-
-uninstall-hook:
-       @for LINK in $(LINKS); do \
-               rm -f $(DESTDIR)$(bindir)/$$LINK; \
-       done
+# EXTRADIST = asingle.c hqx.c macbin.c megatron.c nad.c updcrc.c \
+#      asingle.h megatron.h hqx.h macbin.h nad.h updcrc.h
index 98d045d7ff8215a74d02bae1168a9f1f1b710279..9a06906c0600f07313b1541757b8f2247048fe82 100644 (file)
@@ -21,11 +21,9 @@ AC_PROG_LIBTOOL
 AC_PROG_PERL
 AC_PROG_GREP
 AC_PROG_PS
-
 AM_PROG_CC_C_O
 
 dnl Checks for header files.
-AC_HEADER_DIRENT
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
 AC_CHECK_HEADERS(fcntl.h limits.h stdint.h strings.h time.h sys/param.h sys/fcntl.h sys/file.h sys/ioctl.h sys/time.h sys/mnttab.h sys/statvfs.h sys/stat.h sys/vfs.h mntent.h syslog.h unistd.h termios.h sys/termios.h netdb.h sgtty.h ufs/quota.h mount.h statfs.h sys/types.h dlfcn.h errno.h sys/errno.h sys/uio.h langinfo.h locale.h sys/filio.h)
@@ -1255,7 +1253,8 @@ dnl --------------------- Netatalk Webmin
 NETATALK_WEBMIN
 
 dnl --------------------- last minute substitutions
-
+dnl Request SUSv3 standard interfaces
+CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D__EXTENSIONS__"
 AC_SUBST(LIBS)
 AC_SUBST(CFLAGS)
 AC_SUBST(OVERWRITE_CONFIG)
index d3bf5600b36e1f68c91a15d3b1fadfe2eaa73f71..100e439b3d42bb4d00517ae7ae84f5c2fee837cf 100644 (file)
@@ -712,7 +712,7 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
         openf = O_RDWR|O_CREAT|O_EXCL;
     }
 
-    if ( ad_open( upath, ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
+    if ( ad_open( upath, ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF,
                   openf, 0666, adp) < 0 ) {
         switch ( errno ) {
         case EROFS:
@@ -730,7 +730,7 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
             return( AFPERR_PARAM );
         }
     }
-    if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
+    if ( ad_meta_fileno( adp ) == -1 ) { /* Hard META / HF */
          /* on noadouble volumes, just creating the data fork is ok */
          if (vol_noadouble(vol)) {
              ad_close( adp, ADFLAGS_DF );
index d4247829345d01a298e86baeafab64918c52d0de..4131370460fa6d3839051825d0da2676a71d8c20 100644 (file)
@@ -90,14 +90,16 @@ static int status_server(char *data, const char *server, const struct afp_option
 
     /* extract the obj part of the server */
     Obj = (char *) server;
+#ifndef NO_DDP
     nbp_name(server, &Obj, &Type, &Zone);
+#endif
     if ((size_t)-1 == (len = convert_string( 
-                       options->unixcharset, options->maccharset, 
-                       Obj, -1, buf, sizeof(buf))) ) {
-       len = MIN(strlen(Obj), 31);
+                           options->unixcharset, options->maccharset, 
+                           Obj, -1, buf, sizeof(buf))) ) {
+        len = MIN(strlen(Obj), 31);
        *data++ = len;
        memcpy( data, Obj, len );
-       LOG ( log_error, logtype_afpd, "Could not set servername, using fallback");
+        LOG ( log_error, logtype_afpd, "Could not set servername, using fallback");
     } else {
        *data++ = len;
        memcpy( data, buf, len );
@@ -375,18 +377,18 @@ static size_t status_utf8servername(char *data, int *nameoffset,
 
     /* extract the obj part of the server */
     Obj = (char *) (options->server ? options->server : options->hostname);
+#ifndef NO_DDP
     nbp_name(options->server ? options->server : options->hostname, &Obj, &Type, &Zone);
-
+#endif
     if ((size_t) -1 == (len = convert_string (
-                                       options->unixcharset, CH_UTF8_MAC, 
-                                       Obj, -1, data+sizeof(namelen), maxstatuslen-offset )) ) {
-       LOG ( log_error, logtype_afpd, "Could not set utf8 servername");
+                            options->unixcharset, CH_UTF8_MAC, 
+                            Obj, -1, data+sizeof(namelen), maxstatuslen-offset )) ) {
+        LOG ( log_error, logtype_afpd, "Could not set utf8 servername");
 
-       /* set offset to 0 */
-       memset(begin + *nameoffset, 0, sizeof(offset));
+        /* set offset to 0 */
+        memset(begin + *nameoffset, 0, sizeof(offset));
         data = begin + offset;
-    }
-    else {
+    } else {
        namelen = htons(len);
        memcpy( data, &namelen, sizeof(namelen));
        data += sizeof(namelen);
@@ -395,11 +397,11 @@ static size_t status_utf8servername(char *data, int *nameoffset,
        memcpy(begin + *nameoffset, &offset, sizeof(u_int16_t));
         
         /* Now set the flag ... */
-       memcpy(&status, begin + AFPSTATUS_FLAGOFF, sizeof(status));
-       status = ntohs(status);
-       status |= AFPSRVRINFO_SRVUTF8;
-       status = htons(status);
-       memcpy(begin + AFPSTATUS_FLAGOFF, &status, sizeof(status));
+        memcpy(&status, begin + AFPSTATUS_FLAGOFF, sizeof(status));
+        status = ntohs(status);
+        status |= AFPSRVRINFO_SRVUTF8;
+        status = htons(status);
+        memcpy(begin + AFPSTATUS_FLAGOFF, &status, sizeof(status));
     }
 
     /* return length of buffer */
index 532a620155f7c748835f32a83a53aa882cdc6575..5c105e3181728d34aa85eed89680f8a1b7b5db31 100644 (file)
@@ -363,7 +363,7 @@ int uam_afpserver_option(void *private, const int what, void *option,
 
     switch (what) {
     case UAM_OPTION_USERNAME:
-        *buf = obj->username;
+        *buf = &(obj->username[0]);
         if (len)
             *len = sizeof(obj->username) - 1;
         break;
@@ -491,6 +491,7 @@ int uam_afp_read(void *handle, char *buf, size_t *buflen,
     if (!obj)
         return AFPERR_PARAM;
 
+#ifndef NO_DDP
     switch (obj->proto) {
     case AFPPROTO_ASP:
         if ((len = asp_wrtcont(obj->handle, buf, buflen )) < 0)
@@ -499,6 +500,7 @@ int uam_afp_read(void *handle, char *buf, size_t *buflen,
         break;
 
     case AFPPROTO_DSI:
+#endif
         len = dsi_writeinit(obj->handle, buf, *buflen);
         if (!len || ((len = action(handle, buf, len)) < 0)) {
             dsi_writeflush(obj->handle);
@@ -511,8 +513,10 @@ int uam_afp_read(void *handle, char *buf, size_t *buflen,
                 goto uam_afp_read_err;
             }
         }
+#ifndef NO_DDP
         break;
     }
+#endif
     return 0;
 
 uam_afp_read_err:
index 9b68c3d47d922f90086d7c12ee4c7f3a951ea8fc..8f1fca20aa47e673425360a2d3a79389ed6ce256 100644 (file)
@@ -361,7 +361,6 @@ int setdirmode(const struct vol *vol, const char *name, mode_t mode)
     struct dirent      *dirp;
     DIR                        *dir;
     mode_t              hf_mode;
-    int                 osx = vol->v_adouble == AD_VERSION2_OSX;
     int                 dropbox = (vol->v_flags & AFPVOL_DROPBOX);
     
     mode |= vol->v_dperm;
@@ -380,7 +379,7 @@ int setdirmode(const struct vol *vol, const char *name, mode_t mode)
 
     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
         /* FIXME */
-        if ( *dirp->d_name == '.' && (!osx || dirp->d_name[1] != '_')) {
+        if (*dirp->d_name == '.') {
             continue;
         }
         if ( lstat( dirp->d_name, &st ) < 0 ) {
@@ -389,9 +388,7 @@ int setdirmode(const struct vol *vol, const char *name, mode_t mode)
         }
 
         if (!S_ISDIR(st.st_mode)) {
-           int setmode = (osx && *dirp->d_name == '.')?hf_mode:mode;
-
-           if (setfilmode(dirp->d_name, setmode, &st, vol->v_umask) < 0) {
+           if (setfilmode(dirp->d_name, mode, &st, vol->v_umask) < 0) {
                 LOG(log_error, logtype_afpd, "setdirmode: chmod %s: %s",dirp->d_name, strerror(errno) );
                 return -1;
            }
@@ -509,13 +506,12 @@ int setdirowner(const struct vol *vol, const char *name, const uid_t uid, const
     struct stat                st;
     struct dirent      *dirp;
     DIR                        *dir;
-    int                 osx = vol->v_adouble == AD_VERSION2_OSX;
 
     if (( dir = opendir( name )) == NULL ) {
         return( -1 );
     }
     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
-        if ( *dirp->d_name == '.' && (!osx || dirp->d_name[1] != '_')) {
+        if ( *dirp->d_name == '.') {
             continue;
         }
         if ( lstat( dirp->d_name, &st ) < 0 ) {
index e53599b0149202940c62436733b307106c42abee..3775a816cd8ab79906aee3898c5c382203179230 100644 (file)
@@ -45,6 +45,7 @@ char *strchr (), *strrchr ();
 #include <atalk/logger.h>
 #include <atalk/vfs.h>
 #include <atalk/uuid.h>
+#include <atalk/ea.h>
 
 #ifdef CNID_DB
 #include <atalk/cnid.h>
@@ -151,12 +152,7 @@ typedef struct _special_folder {
 
 static const _special_folder special_folders[] = {
     {"Network Trash Folder",     1,  0777,  1},
-    {"Temporary Items",          1,  0777,  1},
     {".AppleDesktop",            1,  0777,  0},
-#if 0
-    {"TheFindByContentFolder",   0,     0,  1},
-    {"TheVolumeSettingsFolder",  0,     0,  1},
-#endif
     {NULL, 0, 0, 0}};
 
 /* Forward declarations */
@@ -444,16 +440,10 @@ static void volset(struct vol_option *options, struct vol_option *save,
         else if (strcasecmp(val + 1, "xlateupper") == 0)
             options[VOLOPT_CASEFOLD].i_value = AFPVOL_ULOWERMUPPER;
     } else if (optionok(tmp, "adouble:", val)) {
-        if (strcasecmp(val + 1, "v1") == 0)
-            options[VOLOPT_ADOUBLE].i_value = AD_VERSION1;
-#if AD_VERSION == AD_VERSION2
-        else if (strcasecmp(val + 1, "v2") == 0)
+        if (strcasecmp(val + 1, "v2") == 0)
             options[VOLOPT_ADOUBLE].i_value = AD_VERSION2;
-        else if (strcasecmp(val + 1, "osx") == 0)
-            options[VOLOPT_ADOUBLE].i_value = AD_VERSION2_OSX;
-        else if (strcasecmp(val + 1, "sfm") == 0)
-            options[VOLOPT_ADOUBLE].i_value = AD_VERSION1_SFM;
-#endif
+        else if (strcasecmp(val + 1, "ea") == 0)
+            options[VOLOPT_ADOUBLE].i_value = AD_VERSION_EA;
     } else if (optionok(tmp, "options:", val)) {
         char *p;
 
index e9f30dc1cd6e5af77f252f37589aa27ce83ebbb1..e83c2568708036817744212dd88fa2def76e29ff 100644 (file)
@@ -375,7 +375,8 @@ static int pam_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
                     char *rbuf, size_t *rbuflen)
 {
     char *username;
-    int len, ulen;
+    int len;
+    size_t ulen;
     u_int16_t  temp16;
 
     *rbuflen = 0;
index 53337c789f113a27c25c6c3436affedc89b4019e..a1a2ecbd8047ba9346a4248c77ff458a2208f641 100644 (file)
@@ -1,5 +1,4 @@
 /*
- * $Id: adouble.h,v 1.55 2010-03-30 12:55:26 franklahm Exp $
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
  *
 #include <config.h>
 #endif
 
-/* -------------------
- * need pread() and pwrite()
- */
-#ifdef HAVE_PREAD
-
-#ifndef HAVE_PWRITE
-#undef HAVE_PREAD
-#endif
-
-#endif
-
-#ifdef HAVE_PWRITE
-#ifndef HAVE_PREAD
-#undef HAVE_PWRITE
-#endif
-#endif
-
-/*
-  Still have to figure out which platforms really
-  need _XOPEN_SOURCE defined for pread.
-*/
-#if defined(HAVE_PREAD) && !defined(SOLARIS) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(TRU64)
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 500
-#endif
-#endif
-
+#include <inttypes.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-
-#ifdef HAVE_UNISTD_H
-#undef __USE_MISC
-#define __USE_MISC
 #include <unistd.h>
-#endif
-
 #include <sys/cdefs.h>
-
-#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
-#endif
-
 #include <sys/mman.h>
-#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
-#endif
+
 #include <netatalk/endian.h>
 
 /* version info */
-#define AD_VERSION1     0x00010000
-#define SFM_VERSION     AD_VERSION1
-
 #define AD_VERSION2     0x00020000
-#define AD_VERSION2_OSX 0x00020001
-/*
-  #define AD_VERSION1_ADS 0x00010002
-*/
-#define AD_VERSION1_SFM 0x00010003
+#define AD_VERSION_EA   0x00020002
+
+/* default */
 #define AD_VERSION      AD_VERSION2
 
 /*
@@ -99,7 +56,7 @@
  */
 #define ADEID_DFORK         1
 #define ADEID_RFORK         2
-#define ADEID_NAME          3 /* Note: starting with Netatalk 2.1 we do NOT alway set the name */
+#define ADEID_NAME          3
 #define ADEID_COMMENT       4
 #define ADEID_ICONBW        5
 #define ADEID_ICONCOL       6
 #define ADEID_AFPFILEI      14 /* where the rest of the FILEI info goes */
 #define ADEID_DID           15
 
-#if AD_VERSION == AD_VERSION1
-#define ADEID_MAX           16
-#else
 /* netatalk private note fileid reused DID */
 #define ADEID_PRIVDEV       16
 #define ADEID_PRIVINO       17
 #define ADEID_PRIVSYN       18 /* in synch with database */
 #define ADEID_PRIVID        19
-#define ADEID_SFMRESERVE1   20
-#define ADEID_SFMRESERVE2   21
+#define ADEID_MAX           (ADEID_PRIVID + 1)
 
+/* These are the real ids for these entries, as stored in the adouble file */
 #define AD_DEV              0x80444556
 #define AD_INO              0x80494E4F
 #define AD_SYN              0x8053594E
 #define AD_ID               0x8053567E
-#define ADEID_MAX           22
-#endif
 
 /* magic */
 #define AD_APPLESINGLE_MAGIC 0x00051600
 #define AD_APPLEDOUBLE_MAGIC 0x00051607
 #define AD_MAGIC             AD_APPLEDOUBLE_MAGIC
-#define SFM_MAGIC            0x00504641
 
 /* sizes of relevant entry bits */
 #define ADEDLEN_MAGIC       4
 #define ADEDLEN_VERSION     4
 #define ADEDLEN_FILLER      16
 #define ADEDLEN_NENTRIES    2
-
-/* 26 */
-#define AD_HEADER_LEN       (ADEDLEN_MAGIC + ADEDLEN_VERSION + \
-                             ADEDLEN_FILLER + ADEDLEN_NENTRIES)
+#define AD_HEADER_LEN       (ADEDLEN_MAGIC + ADEDLEN_VERSION + ADEDLEN_FILLER + ADEDLEN_NENTRIES)
 #define AD_ENTRY_LEN        12  /* size of a single entry header */
 
-/* v1 field widths */
-#define ADEDLEN_NAME        255
-#define ADEDLEN_COMMENT     200
-#define ADEDLEN_FILEI       16
-#define ADEDLEN_FINDERI     32
-
-/* v2 field widths */
+/* field widths */
+#define ADEDLEN_NAME            255
+#define ADEDLEN_COMMENT         200
+#define ADEDLEN_FILEI           16
+#define ADEDLEN_FINDERI         32
 #define ADEDLEN_FILEDATESI      16
 #define ADEDLEN_SHORTNAME       12 /* length up to 8.3 */
 #define ADEDLEN_AFPFILEI        4
 #define ADEDLEN_PRIVSYN         8
 #define ADEDLEN_PRIVID          4
 
-#define ADEID_NUM_V1            5
 #define ADEID_NUM_V2            13
+#define ADEID_NUM_EA            5
 
-// #define ADEID_NUM_SFM        5
-/* sizeof SFM meta data */
-#define AD_SFM_LEN 60
-
-/* 589 */
-#define AD_DATASZ1      (AD_HEADER_LEN + ADEDLEN_NAME + ADEDLEN_COMMENT + ADEDLEN_FILEI + ADEDLEN_FINDERI + \
-                         (ADEID_NUM_V1 * AD_ENTRY_LEN))
-
-#if AD_DATASZ1 != 589
-#error bad size for AD_DATASZ1
-#endif
-
-#define AD_NEWSZ2       (ADEDLEN_DID + ADEDLEN_AFPFILEI + ADEDLEN_SHORTNAME + ADEDLEN_PRODOSFILEI \
-                         + ADEDLEN_PRIVDEV + ADEDLEN_PRIVINO + ADEDLEN_PRIVSYN + ADEDLEN_PRIVID)
-
-/* 725 */
-#define AD_DATASZ2      (AD_DATASZ1 + AD_NEWSZ2 + ((ADEID_NUM_V2 - ADEID_NUM_V1) * AD_ENTRY_LEN))
-
+#define AD_DATASZ2 (AD_HEADER_LEN + ADEDLEN_NAME + ADEDLEN_COMMENT + ADEDLEN_FILEI + \
+                    ADEDLEN_FINDERI + ADEDLEN_DID + ADEDLEN_AFPFILEI + ADEDLEN_SHORTNAME + \
+                    ADEDLEN_PRODOSFILEI + ADEDLEN_PRIVDEV + ADEDLEN_PRIVINO + \
+                    ADEDLEN_PRIVSYN + ADEDLEN_PRIVID + (ADEID_NUM_V2 * AD_ENTRY_LEN))
 #if AD_DATASZ2 != 741
 #error bad size for AD_DATASZ2
 #endif
 
-#define AD_DATASZ_MAX   1024
-#if AD_VERSION == AD_VERSION1
-#define AD_DATASZ   AD_DATASZ1 /* hold enough for the entries */
-#elif AD_VERSION == AD_VERSION2
-#define AD_DATASZ   AD_DATASZ2
+#define AD_DATASZ_EA (AD_HEADER_LEN + (ADEID_NUM_EA * AD_ENTRY_LEN) + ADEDLEN_FINDERI + \
+                      ADEDLEN_COMMENT + ADEDLEN_FILEDATESI + ADEDLEN_AFPFILEI + ADEDLEN_PRIVID)
+
+#if AD_DATASZ_EA != 342
+#error bad size for AD_DATASZ_EA
 #endif
 
-/*
- * some legacy defines from netatalk-990130
- * (to keep from breaking certain packages)
- *
- */
+#define AD_DATASZ_MAX   1024
 
-#define ADEDOFF_RFORK   589
-#define ADEDOFF_NAME    86
-#define ADEDOFF_COMMENT 341
-#define ADEDOFF_FINDERI 557
-#ifndef ADEDOFF_FILEI
-#define ADEDOFF_FILEI   541
+#if AD_VERSION == AD_VERSION2
+#define AD_DATASZ   AD_DATASZ2
+#elif AD_VERSION == AD_VERSION_EA
+#define AD_DATASZ   AD_DATASZ_EA
 #endif
 
 typedef u_int32_t cnid_t;
 
-/*
- * The header of the AppleDouble Header File looks like this:
- *
- *  NAME            SIZE
- *  ====            ====
- *  Magic           4
- *  Version         4
- *  Home File System    16  (this becomes filler in ad v2)
- *  Number of Entries   2
- *  Entry Descriptors for each entry:
- *      Entry ID    4
- *      Offset      4
- *      Length      4
- */
-
 struct ad_entry {
-    u_int32_t   ade_off;
-    u_int32_t   ade_len;
+    uint32_t   ade_off;
+    uint32_t   ade_len;
 };
 
 typedef struct adf_lock_t {
@@ -243,11 +154,9 @@ typedef struct adf_lock_t {
 
 struct ad_fd {
     int          adf_fd;        /* -1: invalid, -2: symlink */
-
 #ifndef HAVE_PREAD
     off_t        adf_off;
 #endif
-
     char         *adf_syml;
     int          adf_flags;
     int          adf_excl;
@@ -257,7 +166,16 @@ struct ad_fd {
 
 /* some header protection */
 #define AD_INITED  0xad494e54  /* ad"INT" */
-struct adouble_fops;
+
+struct adouble;
+
+struct adouble_fops {
+    char *(*ad_path)(const char *, int);
+    int  (*ad_mkrf)(char *);
+    int  (*ad_rebuild_header)(struct adouble *);
+    int  (*ad_header_read)(struct adouble *, struct stat *);
+    int  (*ad_header_upgrade)(struct adouble *, char *);
+};
 
 struct adouble {
     u_int32_t           ad_magic;
@@ -266,7 +184,6 @@ struct adouble {
     struct ad_entry     ad_eid[ ADEID_MAX ];
     struct ad_fd        ad_data_fork, ad_resource_fork, ad_metadata_fork;
     struct ad_fd        *ad_md; /* either ad_resource or ad_metadata */
-
     int                 ad_flags;    /* This really stores version info too (AD_VERSION*) */
     int                 ad_adflags;  /* ad_open flags adflags like ADFLAGS_DIR */
     unsigned int        ad_inited;
@@ -274,44 +191,27 @@ struct adouble {
     int                 ad_fileordir;
     int                 ad_refcount; /* used in afpd/ofork.c */
     off_t               ad_rlen;     /* ressource fork len with AFP 3.0
-                                        the header parameter size is too small.
-                                     */
+                                        the header parameter size is too small. */
     char                *ad_m_name;   /* mac name for open fork */
     int                 ad_m_namelen;
     struct adouble_fops *ad_ops;
-    u_int16_t       ad_open_forks;      /* open forks (by others) */
-
+    uint16_t            ad_open_forks;      /* open forks (by others) */
 #ifdef USE_MMAPPED_HEADERS
     char                *ad_data;
 #else
-    char        ad_data[AD_DATASZ_MAX];
+    char                ad_data[AD_DATASZ_MAX];
 #endif
 };
 
-struct adouble_fops {
-    char *(*ad_path)(const char *, int);
-    int  (*ad_mkrf)(char *);
-    int  (*ad_rebuild_header)(struct adouble *);
-    int  (*ad_check_header)(struct adouble *, struct stat *);
-    int  (*ad_header_read)(struct adouble *, struct stat *);
-    int  (*ad_header_upgrade)(struct adouble *, char *);
-};
-
 #define ADFLAGS_DF        (1<<0)
-#define ADFLAGS_HF        (1<<1)
-#define ADFLAGS_DIR       (1<<2)
-/*
-#define ADFLAGS_NOADOUBLE (1<<3)
-*/
-#define ADFLAGS_V1COMPAT  (1<<4)
-#define ADFLAGS_NOHF      (1<<5)  /* not an error if no ressource fork */
-#define ADFLAGS_RDONLY    (1<<6)  /* don't try readwrite */
-#define ADFLAGS_OPENFORKS (1<<7)  /* check for open fork in ad_metadata function */
-#define ADFLAGS_RF        (1<<8)
-#define ADFLAGS_MD        ADFLAGS_HF /* (1<<9) */
-#define ADFLAGS_CREATE    (1<<9)
-
-/* adouble v2 cnid cache */
+#define ADFLAGS_RF        (1<<1)
+#define ADFLAGS_HF        (1<<2)
+#define ADFLAGS_DIR       (1<<3)
+#define ADFLAGS_NOHF      (1<<4)  /* not an error if no ressource fork */
+#define ADFLAGS_RDONLY    (1<<5)  /* don't try readwrite */
+#define ADFLAGS_OPENFORKS (1<<6)  /* check for open fork in ad_metadata function */
+#define ADFLAGS_CREATE    (1<<7)
+
 #define ADVOL_NODEV      (1 << 0)
 #define ADVOL_CACHE      (1 << 1)
 #define ADVOL_UNIXPRIV   (1 << 2) /* adouble unix priv */
@@ -462,13 +362,12 @@ extern int ad_excl_lock     (struct adouble * /*adp*/, const u_int32_t /*eid*/);
 #define ad_unlock ad_fcntl_unlock
 
 /* ad_open.c */
+extern uint32_t get_eid   (uint32_t eid);
 extern int ad_setfuid     (const uid_t );
 extern uid_t ad_getfuid   (void );
 extern char *ad_dir       (const char *);
 extern char *ad_path      (const char *, int);
-extern char *ad_path_osx  (const char *, int);
-extern char *ad_path_ads  (const char *, int);
-extern char *ad_path_sfm  (const char *, int);
+extern char *ad_path_ea   (const char *, int);
 extern int ad_mode        (const char *, int);
 extern int ad_mkdir       (const char *, int);
 extern void ad_init       (struct adouble *, int, int );
@@ -480,9 +379,9 @@ extern int ad_metadata    (const char *, int, struct adouble *);
 extern int ad_metadataat  (int, const char *, int, struct adouble *);
 
 #define ad_open_metadata(name, flags, mode, adp)\
-   ad_open(name, ADFLAGS_MD|(flags), O_RDWR |(mode), 0666, (adp))
+   ad_open(name, ADFLAGS_HF | (flags), O_RDWR |(mode), 0666, (adp))
 
-#define ad_close_metadata(adp) ad_close( (adp), ADFLAGS_MD)
+#define ad_close_metadata(adp) ad_close( (adp), ADFLAGS_HF)
 
 /* build a resource fork mode from the data fork mode:
  * remove X mode and extend header to RW if R or W (W if R for locking),
@@ -509,73 +408,43 @@ static inline mode_t ad_hf_mode (mode_t mode)
     return mode;
 }
 
-/* ad_ea.c */
-ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size);
-ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size);
-ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size);
-ssize_t sys_listxattr (const char *path, char *list, size_t size);
-ssize_t sys_llistxattr (const char *path, char *list, size_t size);
-ssize_t sys_flistxattr (int filedes, char *list, size_t size);
-int sys_removexattr (const char *path, const char *name);
-int sys_lremovexattr (const char *path, const char *name);
-int sys_fremovexattr (int filedes, const char *name);
-int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags);
-int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags);
-int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags);
-int sys_copyxattr (const char *src, const char *dst);
-
 /* ad_read.c/ad_write.c */
 extern int     sys_ftruncate(int fd, off_t length);
-
-extern ssize_t ad_read (struct adouble *, const u_int32_t,
-                            const off_t, char *, const size_t);
-extern ssize_t ad_pread (struct ad_fd *, void *, size_t, off_t);
-extern ssize_t ad_write (struct adouble *, const u_int32_t, off_t,
-                             const int, const char *, const size_t);
-extern ssize_t adf_pread  (struct ad_fd *, void *, size_t, off_t);
-extern ssize_t adf_pwrite (struct ad_fd *, const void *, size_t, off_t);
-extern int     ad_dtruncate (struct adouble *, const off_t);
-extern int     ad_rtruncate (struct adouble *, const off_t);
+extern ssize_t ad_read(struct adouble *, uint32_t, off_t, char *, size_t);
+extern ssize_t ad_pread(struct ad_fd *, void *, size_t, off_t);
+extern ssize_t ad_write(struct adouble *, uint32_t, off_t, int, const char *, size_t);
+extern ssize_t adf_pread(struct ad_fd *, void *, size_t, off_t);
+extern ssize_t adf_pwrite(struct ad_fd *, const void *, size_t, off_t);
+extern int     ad_dtruncate(struct adouble *, off_t);
+extern int     ad_rtruncate(struct adouble *, off_t);
 
 /* ad_size.c */
-extern off_t ad_size (const struct adouble *, const u_int32_t );
+extern off_t ad_size (const struct adouble *, uint32_t );
 
 /* ad_mmap.c */
-extern void *ad_mmapread (struct adouble *, const u_int32_t,
-                              const off_t, const size_t);
-extern void *ad_mmapwrite (struct adouble *, const u_int32_t,
-                               const off_t, const int, const size_t);
+extern void *ad_mmapread(struct adouble *, uint32_t, off_t, size_t);
+extern void *ad_mmapwrite(struct adouble *, uint32_t, off_t, int, size_t);
 #define ad_munmap(buf, len)  (munmap((buf), (len)))
 
 /* ad_date.c */
-extern int ad_setdate (struct adouble *, unsigned int, u_int32_t);
-extern int ad_getdate (const struct adouble *, unsigned int, u_int32_t *);
+extern int ad_setdate(struct adouble *, unsigned int, uint32_t);
+extern int ad_getdate(const struct adouble *, unsigned int, uint32_t *);
 
 /* ad_attr.c */
-extern int       ad_setattr (const struct adouble *, const u_int16_t);
-extern int       ad_getattr (const struct adouble *, u_int16_t *);
-
-/* Note: starting with Netatalk 2.1 we do NOT alway set the name */
-extern int       ad_setname (struct adouble *, const char *);
-
-#if AD_VERSION == AD_VERSION2
-extern int       ad_setid (struct adouble *, const dev_t dev,const ino_t ino, const u_int32_t, const u_int32_t, const void *);
-extern u_int32_t ad_getid (struct adouble *, const dev_t, const ino_t, const cnid_t, const void *);
-extern u_int32_t ad_forcegetid (struct adouble *adp);
-#else
-#define ad_setid(a, b, c)
-#endif
+extern int       ad_setattr(const struct adouble *, uint16_t);
+extern int       ad_getattr(const struct adouble *, uint16_t *);
+extern int       ad_setname(struct adouble *, const char *);
+extern int       ad_setid(struct adouble *, dev_t dev, ino_t ino, uint32_t, uint32_t, const void *);
+extern u_int32_t ad_getid(struct adouble *, dev_t, ino_t, cnid_t, const void *);
+extern u_int32_t ad_forcegetid(struct adouble *adp);
 
 #ifdef WITH_SENDFILE
-extern int ad_readfile_init(const struct adouble *ad, 
-                                      const int eid, off_t *off,
-                                      const int end);
+extern int ad_readfile_init(const struct adouble *ad, int eid, off_t *off, int end);
 #endif
 
 #if 0
 #ifdef HAVE_SENDFILE_WRITE
-extern ssize_t ad_writefile (struct adouble *, const int,
-                                 const int, off_t, const int, const size_t);
+extern ssize_t ad_writefile(struct adouble *, int, int, off_t, int, size_t);
 #endif /* HAVE_SENDFILE_WRITE */
 #endif /* 0 */
 
index 0616774da18da49e2afb74ccc971bd13d40b6d19..713ed1fba647a49848f5e4fcb5ff6f7deec0f5ee 100644 (file)
@@ -9,6 +9,7 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 #include <sys/time.h>
+#include <sys/socket.h>
 #include <signal.h>
 
 #include <netinet/in.h>
 #include <atalk/server_child.h>
 #include <netatalk/endian.h>
 
-#ifdef __OpenBSD__
-#include <sys/socket.h>
-#endif
-
 /* What a DSI packet looks like:
  0                               32
  |-------------------------------|
index c0165a1a257f210999055d8a271bc81dadf9e2a8..3c92529b10f437d08de7223ac605fb8e4c4e1e01 100644 (file)
@@ -1,5 +1,4 @@
 /*
-   $Id: ea.h,v 1.11 2010-03-12 15:16:49 franklahm Exp $
    Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
    This program is free software; you can redistribute it and/or modify
 #include <config.h>
 #endif
 
+#if HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#elif HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
+
+#ifdef HAVE_SYS_EA_H
+#include <sys/ea.h>
+#endif
+
+#ifdef HAVE_SYS_EXTATTR_H
+#include <sys/extattr.h>
+#endif
+
 #ifdef HAVE_SOLARIS_ACLS
 #include <sys/acl.h>
 #endif
 
+#ifndef ENOATTR
+#define ENOATTR ENODATA
+#endif
+
 #include <atalk/vfs.h>
 
 /*
@@ -56,6 +73,26 @@ enum {
 #define XATTR_REPLACE 0x2       /* set value, fail if attr does not exist */
 #endif
 
+/* Names for our Extended Attributes adouble data */
+#define AD_EA_META "org.netatalk.Metadata"
+#define AD_EA_RESO "org.netatalk.ResourceFork"
+
+/****************************************************************************************
+ * Wrappers for native EA functions taken from Samba
+ ****************************************************************************************/
+ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size);
+ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size);
+ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size);
+ssize_t sys_listxattr (const char *path, char *list, size_t size);
+ssize_t sys_llistxattr (const char *path, char *list, size_t size);
+ssize_t sys_flistxattr (int filedes, char *list, size_t size);
+int sys_removexattr (const char *path, const char *name);
+int sys_lremovexattr (const char *path, const char *name);
+int sys_fremovexattr (int filedes, const char *name);
+int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags);
+int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags);
+int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags);
+int sys_copyxattr (const char *src, const char *dst);
 
 /****************************************************************************************
  * Stuff for our implementation of storing EAs in files in .AppleDouble dirs
index 63da2935df0733c74fceb9f31aee241b7c3f4cef..ba55bc9b0f381d66089e9d35e10046143e984951 100644 (file)
 
 #include <sys/cdefs.h>
 #include <sys/types.h>
-#ifdef HAVE_UNISTD_H
+#include <sys/socket.h>
 #include <unistd.h>
-#endif /* HAVE_UNISTD_H */
+
+#ifndef NO_DDP
 #include <netatalk/at.h>
+#endif
 #include <atalk/unicode.h>
 
 /* exit error codes */
@@ -56,7 +58,9 @@ extern void freeifacelist(char **);
 
 #define diatolower(x)     _dialowermap[(unsigned char) (x)]
 #define diatoupper(x)     _diacasemap[(unsigned char) (x)]
+#ifndef NO_DDP
 extern int atalk_aton     (char *, struct at_addr *);
+#endif
 extern void bprint        (char *, int);
 extern int strdiacasecmp  (const char *, const char *);
 extern int strndiacasecmp (const char *, const char *, size_t);
@@ -137,6 +141,7 @@ extern int compare_ip(const struct sockaddr *sa1, const struct sockaddr *sa2);
  * unix.c
  *****************************************************************/
 
+extern const char *abspath(const char *name);
 extern const char *getcwdpath(void);
 extern char *stripped_slashes_basename(char *p);
 extern int lchdir(const char *dir);
index 4c7500d6dd033db505b49ddc9114e2c403a55473..a70237318ff84c457c5cf8dbae43b39c12123a4a 100644 (file)
@@ -1,7 +1,7 @@
 
 # Makefile.am for libatalk/
 
-SUBDIRS = acl adouble asp atp bstring compat cnid dsi nbp netddp tdb util unicode vfs
+SUBDIRS = acl adouble bstring compat cnid dsi tdb util unicode vfs
 
 lib_LTLIBRARIES = libatalk.la
 
@@ -10,13 +10,9 @@ libatalk_la_SOURCES = dummy.c
 libatalk_la_LIBADD  = \
        acl/libacl.la \
        adouble/libadouble.la   \
-       asp/libasp.la           \
-       atp/libatp.la           \
        bstring/libbstring.la \
        compat/libcompat.la     \
        dsi/libdsi.la           \
-       nbp/libnbp.la           \
-       netddp/libnetddp.la     \
        util/libutil.la         \
        tdb/libtdb.la       \
        unicode/libunicode.la \
@@ -25,13 +21,9 @@ libatalk_la_LIBADD  = \
 libatalk_la_DEPENDENCIES = \
        acl/libacl.la \
        adouble/libadouble.la   \
-       asp/libasp.la           \
-       atp/libatp.la           \
        bstring/libbstring.la \
        compat/libcompat.la     \
        dsi/libdsi.la           \
-       nbp/libnbp.la           \
-       netddp/libnetddp.la     \
        util/libutil.la         \
        tdb/libtdb.la       \
        unicode/libunicode.la \
@@ -39,3 +31,16 @@ libatalk_la_DEPENDENCIES = \
 
 libatalk_la_LDFLAGS = -static
 
+if USE_APPLETALK
+SUBDIRS += asp atp nbp netddp
+libatalk_la_LIBADD += \
+       asp/libasp.la           \
+       atp/libatp.la           \
+       nbp/libnbp.la           \
+       netddp/libnetddp.la
+libatalk_la_DEPENDENCIES += \
+       asp/libasp.la           \
+       atp/libatp.la           \
+       nbp/libnbp.la           \
+       netddp/libnetddp.la
+endif
index be422aac38c7498d89e56c0f004f8cbe0374cff2..57933f088e40d2e9d4210739af9050ca0683fe88 100644 (file)
@@ -52,7 +52,7 @@ int get_nfsv4_acl(const char *name, ace_t **retAces)
         /* sorry, no ACLs for symlinks */
         return 0;
 
-    if ( ! (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) {
+    if ( ! ((S_ISREG(st.st_mode)) || (S_ISDIR(st.st_mode)))) {
         LOG(log_warning, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): special", getcwdpath(), name);
         return 0;
     }
index 8b3a32041325a5d405cc114fc1208eba38aa5456..484961eeeb22597330a395504858bd36da24d4d3 100644 (file)
@@ -19,14 +19,7 @@ int ad_getattr(const struct adouble *ad, u_int16_t *attr)
     u_int16_t fflags;
     *attr = 0;
 
-    if (ad->ad_version == AD_VERSION1) {
-        if (ad_getentryoff(ad, ADEID_FILEI)) {
-            memcpy(attr, ad_entry(ad, ADEID_FILEI) + FILEIOFF_ATTR,
-                   sizeof(u_int16_t));
-        }
-    }
-#if AD_VERSION == AD_VERSION2
-    else if (ad->ad_version == AD_VERSION2) {
+    if (ad->ad_version == AD_VERSION2) {
         if (ad_getentryoff(ad, ADEID_AFPFILEI)) {
             memcpy(attr, ad_entry(ad, ADEID_AFPFILEI) + AFPFILEIOFF_ATTR, 2);
 
@@ -48,9 +41,6 @@ int ad_getattr(const struct adouble *ad, u_int16_t *attr)
             }
         }
     }
-#endif
-    else
-        return -1;
 
     *attr |= htons(ad->ad_open_forks);
 
@@ -70,14 +60,7 @@ int ad_setattr(const struct adouble *ad, const u_int16_t attribute)
     if (ad->ad_adflags & ADFLAGS_DIR)
         attr &= ~(ATTRBIT_MULTIUSER | ATTRBIT_NOWRITE | ATTRBIT_NOCOPY);
 
-    if (ad->ad_version == AD_VERSION1) {
-        if (ad_getentryoff(ad, ADEID_FILEI)) {
-            memcpy(ad_entry(ad, ADEID_FILEI) + FILEIOFF_ATTR, &attr,
-                   sizeof(attr));
-        }
-    }
-#if AD_VERSION == AD_VERSION2
-    else if (ad->ad_version == AD_VERSION2) {
+    if (ad->ad_version == AD_VERSION2) {
         if (ad_getentryoff(ad, ADEID_AFPFILEI) && ad_getentryoff(ad, ADEID_FINDERI)) {
             memcpy(ad_entry(ad, ADEID_AFPFILEI) + AFPFILEIOFF_ATTR, &attr, sizeof(attr));
             
@@ -98,9 +81,6 @@ int ad_setattr(const struct adouble *ad, const u_int16_t attribute)
             memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &fflags, 2);
         }
     }
-#endif
-    else
-        return -1;
 
     return 0;
 }
@@ -109,7 +89,6 @@ int ad_setattr(const struct adouble *ad, const u_int16_t attribute)
  * save file/folder ID in AppleDoubleV2 netatalk private parameters
  * return 1 if resource fork has been modified
  */
-#if AD_VERSION == AD_VERSION2
 int ad_setid (struct adouble *adp, const dev_t dev, const ino_t ino , const u_int32_t id, const cnid_t did, const void *stamp)
 {
     if ((adp->ad_flags == AD_VERSION2) && (adp->ad_options & ADVOL_CACHE)) {
@@ -183,7 +162,6 @@ u_int32_t ad_forcegetid (struct adouble *adp)
     }
     return 0;
 }
-#endif
 
 /* -----------------
  * set resource fork filename attribute.
index 132c4f1ae7935b151b68ce34d269f3b91cd68616..ab1e0a7f963c6374c51347df3d5be6094d415545 100644 (file)
@@ -5,63 +5,39 @@
 #include <string.h>
 #include <atalk/adouble.h>
 
-int ad_setdate(struct adouble *ad, 
-              unsigned int dateoff, u_int32_t date)
+int ad_setdate(struct adouble *ad,
+               unsigned int dateoff, u_int32_t date)
 {
-  int xlate = (dateoff & AD_DATE_UNIX);
+    int xlate = (dateoff & AD_DATE_UNIX);
 
-  dateoff &= AD_DATE_MASK;
-  if (xlate)
-    date = AD_DATE_FROM_UNIX(date);
+    dateoff &= AD_DATE_MASK;
+    if (xlate)
+        date = AD_DATE_FROM_UNIX(date);
 
-  if (ad->ad_version == AD_VERSION1) {
-
-    if (!ad_getentryoff(ad, ADEID_FILEI))
-        return -1;
-
-    if (dateoff > AD_DATE_BACKUP)
-      return -1;
-    memcpy(ad_entry(ad, ADEID_FILEI) + dateoff, &date, sizeof(date));
-
-  } else if (ad->ad_version == AD_VERSION2) {
     if (!ad_getentryoff(ad, ADEID_FILEDATESI))
         return -1;
-        
+
     if (dateoff > AD_DATE_ACCESS)
         return -1;
     memcpy(ad_entry(ad, ADEID_FILEDATESI) + dateoff, &date, sizeof(date));
 
-  } else 
-    return -1;
-
-  return 0;
+    return 0;
 }
 
 int ad_getdate(const struct adouble *ad,
-              unsigned int dateoff, u_int32_t *date) 
+               unsigned int dateoff, u_int32_t *date)
 {
-  int xlate = (dateoff & AD_DATE_UNIX);
-
-  dateoff &= AD_DATE_MASK;
-  if (ad->ad_version == AD_VERSION1) {
-    if (dateoff > AD_DATE_BACKUP)
-      return -1;
-    if (!ad_getentryoff(ad, ADEID_FILEI))
-        return -1;
-    memcpy(date, ad_entry(ad, ADEID_FILEI) + dateoff, sizeof(u_int32_t));
+    int xlate = (dateoff & AD_DATE_UNIX);
 
-  } else if (ad->ad_version == AD_VERSION2) {
+    dateoff &= AD_DATE_MASK;
     if (!ad_getentryoff(ad, ADEID_FILEDATESI))
         return -1;
 
     if (dateoff > AD_DATE_ACCESS)
-      return -1;
+        return -1;
     memcpy(date, ad_entry(ad, ADEID_FILEDATESI) + dateoff, sizeof(u_int32_t));
 
-  } else 
-    return -1;
-
-  if (xlate)
-    *date = AD_DATE_TO_UNIX(*date);
-  return 0;
+    if (xlate)
+        *date = AD_DATE_TO_UNIX(*date);
+    return 0;
 }
index 1f4d8b331b4bb92eafcb3a15c4d20dffe28aa6de..185339601c4c4a4b2bc688e73d968d45811c3adc 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
+ * Copyright (c) 2010      Frank Lahm
  * All Rights Reserved.
  *
  * Permission to use, copy, modify, and distribute this software and
 #endif /* HAVE_CONFIG_H */
 
 #include <string.h>
-#include <atalk/adouble.h>
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
 
-#include "ad_private.h"
-#if AD_VERSION == AD_VERSION1
-
-#define EID_DISK(a) (a)
+#include <atalk/adouble.h>
+#include <atalk/ea.h>
+#include <atalk/logger.h>
 
-#else
+#include "ad_private.h"
 
 static const u_int32_t set_eid[] = {
     0,1,2,3,4,5,6,7,8,
@@ -46,22 +44,18 @@ static const u_int32_t set_eid[] = {
 };
 
 #define EID_DISK(a) (set_eid[a])
-#endif
 
-/* rebuild the adouble header
- * XXX should be in a separate file ?
+/*
+ * Rebuild any header information that might have changed.
  */
 int  ad_rebuild_adouble_header(struct adouble *ad)
 {
     u_int32_t       eid;
     u_int32_t       temp;
-
     u_int16_t       nent;
     char        *buf, *nentp;
+    int             len;
 
-    /*
-     * Rebuild any header information that might have changed.
-     */
     buf = ad->ad_data;
 
     temp = htonl( ad->ad_magic );
@@ -72,7 +66,6 @@ int  ad_rebuild_adouble_header(struct adouble *ad)
     memcpy(buf, &temp, sizeof( temp ));
     buf += sizeof( temp );
 
-    memcpy(buf, ad->ad_filler, sizeof( ad->ad_filler ));
     buf += sizeof( ad->ad_filler );
 
     nentp = buf;
@@ -96,7 +89,21 @@ int  ad_rebuild_adouble_header(struct adouble *ad)
     }
     nent = htons( nent );
     memcpy(nentp, &nent, sizeof( nent ));
-    return ad_getentryoff(ad, ADEID_RFORK);
+
+    switch (ad->ad_flags) {
+    case AD_VERSION2:
+        len = ad_getentryoff(ad, ADEID_RFORK);
+        break;
+    case AD_VERSION_EA:
+        len = AD_DATASZ_EA;
+        break;
+    default:
+        LOG(log_error, logtype_afpd, "Unexpected adouble version");
+        len = 0;
+        break;
+    }
+
+    return len;
 }
 
 /* -------------------
@@ -134,57 +141,37 @@ int ad_copy_header(struct adouble *add, struct adouble *ads)
     return 0;
 }
 
-/* ------------------- */
-int  ad_rebuild_sfm_header(struct adouble *ad)
-{
-    u_int32_t       temp;
-
-    u_int16_t       attr;
-    char        *buf;
-
-    /*
-     * Rebuild any header information that might have changed.
-     */
-    buf = ad->ad_data;
-    /* FIXME */
-/*    temp = htonl( ad->ad_magic ); */
-    temp = ad->ad_magic;
-    memcpy(buf, &temp, sizeof( temp ));
-
-/*    temp = htonl( ad->ad_version ); */
-    temp = ad->ad_version;
-    memcpy(buf +4, &temp, sizeof( temp ));
-
-    /* need to save attrib */
-    if (!ad_getattr(ad, &attr)) {
-        attr &= ~htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN);
-
-        memcpy(buf +48 +4, &attr, sizeof(attr));
-
-    }
-    return AD_SFM_LEN;
-}
-
-
-int ad_flush( struct adouble *ad)
+int ad_flush(struct adouble *ad)
 {
     int len;
 
     if (( ad->ad_md->adf_flags & O_RDWR )) {
-        /* sync our header */
-        if (ad->ad_rlen > 0xffffffff) {
-            ad_setentrylen(ad, ADEID_RFORK, 0xffffffff);
-        }
-        else {
-            ad_setentrylen(ad, ADEID_RFORK, ad->ad_rlen);
+        if (ad_getentryoff(ad, ADEID_RFORK)) {
+            if (ad->ad_rlen > 0xffffffff)
+                ad_setentrylen(ad, ADEID_RFORK, 0xffffffff);
+            else
+                ad_setentrylen(ad, ADEID_RFORK, ad->ad_rlen);
         }
         len = ad->ad_ops->ad_rebuild_header(ad);
 
-        if (adf_pwrite(ad->ad_md, ad->ad_data, len, 0) != len) {
-            if ( errno == 0 ) {
-                errno = EIO;
+        switch (ad->ad_flags) {
+        case AD_VERSION2:
+            if (adf_pwrite(ad->ad_md, ad->ad_data, len, 0) != len) {
+                if (errno == 0)
+                    errno = EIO;
+                return( -1 );
             }
-            return( -1 );
+            break;
+        case AD_VERSION_EA:
+            if (sys_fsetxattr(ad->ad_md->adf_fd, AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0) != 0) {
+                LOG(log_error, logtype_afpd, "ad_flush: sys_fsetxattr error: %s",
+                    strerror(errno));
+                return -1;
+            }
+            break;
+        default:
+            LOG(log_error, logtype_afpd, "ad_flush: unexpected adouble version");
+            return -1;
         }
     }
 
@@ -214,7 +201,7 @@ int ad_close( struct adouble *ad, int adflags)
         return err;
     }
 
-    /* meta /resource fork */
+    /* meta/resource fork */
 
     if ( ad_meta_fileno(ad) != -1 && !(--ad->ad_md->adf_refcount)) {
         if ( close( ad_meta_fileno(ad) ) < 0 ) {
@@ -224,21 +211,5 @@ int ad_close( struct adouble *ad, int adflags)
         adf_lock_free(ad->ad_md);
     }
 
-    if (ad->ad_flags != AD_VERSION1_SFM) {
-        return err;
-    }
-
-    if ((adflags & ADFLAGS_DIR)) {
-        return err;
-    }
-
-    if ( ad_reso_fileno(ad) != -1 && !(--ad->ad_resource_fork.adf_refcount)) {
-        if ( close( ad_reso_fileno(ad) ) < 0 ) {
-            err = -1;
-        }
-        ad_reso_fileno(ad) = -1;
-        adf_lock_free(&ad->ad_resource_fork);
-    }
-
     return err;
 }
index 30a1303340c6fdef00a885c63d0ea00f5a7b8199..688ec4b9624ea439dbcc2a14ea1b08f787f161fd 100644 (file)
@@ -632,7 +632,7 @@ void ad_fcntl_unlock(struct adouble *ad, const int fork)
     adf_unlock(&ad->ad_resource_fork, fork);
   }
 
-  if (ad->ad_flags != AD_VERSION1_SFM) {
+  if (ad->ad_flags != AD_VERSION_EA) {
     return;
   }
   if (ad_meta_fileno(ad) != -1) {
index 7adb4abda262c7261a8197463d36f9369a2a7426..fd6e9f56afed07addc3d02e6ab1e97033cfedf28 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
+ * Copyright (c) 2010 Frank Lahm
+ *
  * All Rights Reserved.
  *
  * Permission to use, copy, modify, and distribute this software and
 #endif /* HAVE_CONFIG_H */
 
 #include <errno.h>
-
-#include <atalk/adouble.h>
 #include <sys/param.h>
-#include <atalk/logger.h>
+#include <stdlib.h>
+#include <string.h>
 
+#include <atalk/logger.h>
+#include <atalk/adouble.h>
 #include <atalk/util.h>
-#include <string.h>
+#include <atalk/ea.h>
 
 #include "ad_private.h"
-#include <stdlib.h>
 
 #ifndef MAX
 #define MAX(a, b)  ((a) < (b) ? (b) : (a))
 #endif /* ! MAX */
 
+#ifdef  HAVE_PREAD
+# define AD_SET(a)
+#else
+# define AD_SET(a) a = 0
+#endif
+
 /*
  * AppleDouble entry default offsets.
  * The layout looks like this:
@@ -74,9 +82,6 @@
  *
  * so, all we need to do is replace FILEI with FILEDATESI, move RFORK,
  * and add in the new fields.
- *
- * NOTE: the HFS module will need similar modifications to interact with
- * afpd correctly.
  */
 
 #define ADEDOFF_MAGIC        (0)
 #undef ADEDOFF_FILEI
 #endif /* ADEDOFF_FILEI */
 
-#define ADEDOFF_NAME_V1      (AD_HEADER_LEN + ADEID_NUM_V1*AD_ENTRY_LEN)
-#define ADEDOFF_COMMENT_V1   (ADEDOFF_NAME_V1 + ADEDLEN_NAME)
-#define ADEDOFF_FILEI        (ADEDOFF_COMMENT_V1 + ADEDLEN_COMMENT)
-#define ADEDOFF_FINDERI_V1   (ADEDOFF_FILEI + ADEDLEN_FILEI)
-#define ADEDOFF_RFORK_V1     (ADEDOFF_FINDERI_V1 + ADEDLEN_FINDERI)
-
 /* i stick things in a slightly different order than their eid order in
  * case i ever want to separate RootInfo behaviour from the rest of the
  * stuff. */
+
+/* ad:v2 */
 #define ADEDOFF_NAME_V2      (AD_HEADER_LEN + ADEID_NUM_V2*AD_ENTRY_LEN)
 #define ADEDOFF_COMMENT_V2   (ADEDOFF_NAME_V2 + ADEDLEN_NAME)
 #define ADEDOFF_FILEDATESI   (ADEDOFF_COMMENT_V2 + ADEDLEN_COMMENT)
 #define ADEDOFF_FINDERI_V2   (ADEDOFF_FILEDATESI + ADEDLEN_FILEDATESI)
-#define ADEDOFF_DID      (ADEDOFF_FINDERI_V2 + ADEDLEN_FINDERI)
+#define ADEDOFF_DID          (ADEDOFF_FINDERI_V2 + ADEDLEN_FINDERI)
 #define ADEDOFF_AFPFILEI     (ADEDOFF_DID + ADEDLEN_DID)
 #define ADEDOFF_SHORTNAME    (ADEDOFF_AFPFILEI + ADEDLEN_AFPFILEI)
 #define ADEDOFF_PRODOSFILEI  (ADEDOFF_SHORTNAME + ADEDLEN_SHORTNAME)
 #define ADEDOFF_PRIVINO      (ADEDOFF_PRIVDEV + ADEDLEN_PRIVDEV)
 #define ADEDOFF_PRIVSYN      (ADEDOFF_PRIVINO + ADEDLEN_PRIVINO)
 #define ADEDOFF_PRIVID       (ADEDOFF_PRIVSYN + ADEDLEN_PRIVSYN)
-
 #define ADEDOFF_RFORK_V2     (ADEDOFF_PRIVID + ADEDLEN_PRIVID)
 
-#define ADEID_NUM_OSX        2
-#define ADEDOFF_FINDERI_OSX  (AD_HEADER_LEN + ADEID_NUM_OSX*AD_ENTRY_LEN)
-#define ADEDOFF_RFORK_OSX    (ADEDOFF_FINDERI_OSX + ADEDLEN_FINDERI)
-
-/* we keep local copies of a bunch of stuff so that we can initialize things
- * correctly. */
+/* ad:ea */
+#define ADEDOFF_FINDERI_EA   (AD_HEADER_LEN + ADEID_NUM_EA * AD_ENTRY_LEN)
+#define ADEDOFF_COMMENT_EA   (ADEDOFF_FINDERI_EA + ADEDLEN_FINDERI)
+#define ADEDOFF_FILEDATESI_EA (ADEDOFF_COMMENT_EA + ADEDLEN_COMMENT)
+#define ADEDOFF_AFPFILEI_EA  (ADEDOFF_FILEDATESI_EA + ADEDLEN_FILEDATESI)
 
 /* this is to prevent changing timezones from causing problems with
-   localtime volumes. the screw-up is 30 years. we use a delta of 5
-   years.  */
+   localtime volumes. the screw-up is 30 years. we use a delta of 5 years */
 #define TIMEWARP_DELTA 157680000
 
-
 struct entry {
-    u_int32_t id, offset, len;
+    uint32_t id, offset, len;
 };
 
-static const struct entry entry_order1[ADEID_NUM_V1 +1] = {
-    {ADEID_NAME,    ADEDOFF_NAME_V1,    ADEDLEN_INIT},      /* 3 */
-    {ADEID_COMMENT, ADEDOFF_COMMENT_V1, ADEDLEN_INIT},      /* 4 */
-    {ADEID_FILEI,   ADEDOFF_FILEI,      ADEDLEN_FILEI},     /* 7 */
-    {ADEID_FINDERI, ADEDOFF_FINDERI_V1, ADEDLEN_FINDERI},   /* 9 */
-    {ADEID_RFORK,   ADEDOFF_RFORK_V1,   ADEDLEN_INIT},      /* 2 */
-    {0, 0, 0}
+/* --------------------------- */
+static uid_t default_uid = -1;
+
+/* Forward declarations */
+static int ad_mkrf(char *path);
+static int ad_header_read(struct adouble *ad, struct stat *hst);
+static int ad_header_upgrade(struct adouble *ad, char *name);
+
+static int ad_mkrf_ea(char *path);
+static int ad_header_read_ea(struct adouble *ad, struct stat *hst);
+static int ad_header_upgrade_ea(struct adouble *ad, char *name);
+
+static struct adouble_fops ad_adouble = {
+    &ad_path,
+    &ad_mkrf,
+    &ad_rebuild_adouble_header,
+    &ad_header_read,
+    &ad_header_upgrade,
 };
 
-#if AD_VERSION == AD_VERSION1
-#define DISK_EID(ad, a) (a)
+static struct adouble_fops ad_adouble_ea = {
+    &ad_path_ea,
+    &ad_mkrf_ea,
+    &ad_rebuild_adouble_header,
+    &ad_header_read_ea,
+    &ad_header_upgrade_ea,
+};
+
+static const struct entry entry_order2[ADEID_NUM_V2 + 1] = {
+    {ADEID_NAME,        ADEDOFF_NAME_V2,     ADEDLEN_INIT},
+    {ADEID_COMMENT,     ADEDOFF_COMMENT_V2,  ADEDLEN_INIT},
+    {ADEID_FILEDATESI,  ADEDOFF_FILEDATESI,  ADEDLEN_FILEDATESI},
+    {ADEID_FINDERI,     ADEDOFF_FINDERI_V2,  ADEDLEN_FINDERI},
+    {ADEID_DID,         ADEDOFF_DID,         ADEDLEN_DID},
+    {ADEID_AFPFILEI,    ADEDOFF_AFPFILEI,    ADEDLEN_AFPFILEI},
+    {ADEID_SHORTNAME,   ADEDOFF_SHORTNAME,   ADEDLEN_INIT},
+    {ADEID_PRODOSFILEI, ADEDOFF_PRODOSFILEI, ADEDLEN_PRODOSFILEI},
+    {ADEID_PRIVDEV,     ADEDOFF_PRIVDEV,     ADEDLEN_INIT},
+    {ADEID_PRIVINO,     ADEDOFF_PRIVINO,     ADEDLEN_INIT},
+    {ADEID_PRIVSYN,     ADEDOFF_PRIVSYN,     ADEDLEN_INIT},
+    {ADEID_PRIVID,      ADEDOFF_PRIVID,      ADEDLEN_INIT},
+    {ADEID_RFORK,       ADEDOFF_RFORK_V2,    ADEDLEN_INIT},
+    {0, 0, 0}
+};
 
-#else /* AD_VERSION == AD_VERSION2 */
+/* Using Extended Attributes */
+static const struct entry entry_order_ea[ADEID_NUM_EA + 1] = {
+    {ADEID_FINDERI,    ADEDOFF_FINDERI_EA,    ADEDLEN_FINDERI},
+    {ADEID_COMMENT,    ADEDOFF_COMMENT_EA,    ADEDLEN_INIT},
+    {ADEID_FILEDATESI, ADEDOFF_FILEDATESI_EA, ADEDLEN_FILEDATESI},
+    {ADEID_AFPFILEI,   ADEDOFF_AFPFILEI_EA,   ADEDLEN_AFPFILEI},
+    {0, 0, 0}
+};
 
-static u_int32_t get_eid(struct adouble *ad, u_int32_t eid)
+uint32_t get_eid(uint32_t eid)
 {
     if (eid <= 15)
         return eid;
-    if (ad->ad_version == AD_VERSION1)
-        return 0;
     if (eid == AD_DEV)
         return ADEID_PRIVDEV;
     if (eid == AD_INO)
@@ -165,343 +200,78 @@ static u_int32_t get_eid(struct adouble *ad, u_int32_t eid)
     return 0;
 }
 
-#define DISK_EID(ad, a) get_eid(ad, a)
-
-static const struct entry entry_order2[ADEID_NUM_V2 +1] = {
-    {ADEID_NAME, ADEDOFF_NAME_V2, ADEDLEN_INIT},
-    {ADEID_COMMENT, ADEDOFF_COMMENT_V2, ADEDLEN_INIT},
-    {ADEID_FILEDATESI, ADEDOFF_FILEDATESI, ADEDLEN_FILEDATESI},
-    {ADEID_FINDERI, ADEDOFF_FINDERI_V2, ADEDLEN_FINDERI},
-    {ADEID_DID, ADEDOFF_DID, ADEDLEN_DID},
-    {ADEID_AFPFILEI, ADEDOFF_AFPFILEI, ADEDLEN_AFPFILEI},
-    {ADEID_SHORTNAME, ADEDOFF_SHORTNAME, ADEDLEN_INIT},
-    {ADEID_PRODOSFILEI, ADEDOFF_PRODOSFILEI, ADEDLEN_PRODOSFILEI},
-    {ADEID_PRIVDEV,     ADEDOFF_PRIVDEV, ADEDLEN_INIT},
-    {ADEID_PRIVINO,     ADEDOFF_PRIVINO, ADEDLEN_INIT},
-    {ADEID_PRIVSYN,     ADEDOFF_PRIVSYN, ADEDLEN_INIT},
-    {ADEID_PRIVID,     ADEDOFF_PRIVID, ADEDLEN_INIT},
-    {ADEID_RFORK, ADEDOFF_RFORK_V2, ADEDLEN_INIT},
-
-    {0, 0, 0}
-};
-
-/* OS X adouble finder info and resource fork only
- */
-static const struct entry entry_order_osx[ADEID_NUM_OSX +1] = {
-    {ADEID_FINDERI, ADEDOFF_FINDERI_OSX, ADEDLEN_FINDERI},
-    {ADEID_RFORK, ADEDOFF_RFORK_OSX, ADEDLEN_INIT},
-
-    {0, 0, 0}
-};
-
-#define ADEID_NUM_SFM 3
-static const struct entry entry_order_sfm[ADEID_NUM_SFM +1] = {
-    {ADEID_FINDERI,     16,         ADEDLEN_FINDERI},   /* 9 */
-    {ADEID_SFMRESERVE2, 16+32,      6},                 /* 21 */
-    {ADEID_FILEI,       60,         ADEDLEN_FILEI},     /* 7 */
-
-    {0, 0, 0}
-};
-
-#endif /* AD_VERSION == AD_VERSION2 */
-
-#if AD_VERSION == AD_VERSION2
-
-/* update a version 2 adouble resource fork with our private entries */
-static int ad_update(struct adouble *ad, const char *path)
+/* ----------------------------------- */
+static int new_ad_header(const char *path, struct adouble *ad, int adflags)
 {
-    struct stat st;
-    u_int16_t nentries = 0;
-    off_t     off, shiftdata=0;
     const struct entry  *eid;
-    static off_t entry_len[ADEID_MAX];
-    static char  databuf[ADEID_MAX][256], *buf;
-    int fd;
-    int ret = -1;
-
-    /* check to see if we should convert this header. */
-    if (!path || ad->ad_flags != AD_VERSION2)
-        return 0;
-
-    LOG(log_maxdebug, logtype_default, "ad_update: checking whether '%s' needs an upgrade.", path);
-
-    if (!(ad->ad_md->adf_flags & O_RDWR)) {
-        /* we were unable to open the file read write the last time */
-        return 0;
-    }
-
-    if (ad->ad_eid[ADEID_RFORK].ade_off) {
-        shiftdata = ADEDOFF_RFORK_V2 -ad->ad_eid[ADEID_RFORK].ade_off;
-    }
-
-    memcpy(&nentries, ad->ad_data + ADEDOFF_NENTRIES, sizeof( nentries ));
-    nentries = ntohs( nentries );
-
-    if ( shiftdata == 0 && nentries == ADEID_NUM_V2)
-        return 0;
-
-    memset(entry_len, 0, sizeof(entry_len));
-    memset(databuf, 0, sizeof(databuf));
-
-    /* bail if we can't get a lock */
-    if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0, 0) < 0)
-        goto bail_err;
-
-    fd = ad->ad_md->adf_fd;
-
-    if (fstat(fd, &st)) {
-        goto bail_lock;
-    }
-
-    if (st.st_size > 0x7fffffff) {
-        LOG(log_debug, logtype_default, "ad_update: file '%s' too big for update.", path);
-        errno = EIO;
-        goto bail_lock;
-    }
-
-    off = ad->ad_eid[ADEID_RFORK].ade_off;
-    if (off > st.st_size) {
-        LOG(log_error, logtype_default, "ad_update: invalid resource fork offset. (off: %u)", off);
-        errno = EIO;
-        goto bail_lock;
-    }
-
-    if (ad->ad_eid[ADEID_RFORK].ade_len > st.st_size - off) {
-        LOG(log_error, logtype_default, "ad_update: invalid resource fork length. (rfork len: %u)", ad->ad_eid[ADEID_RFORK].ade_len);
-        errno = EIO;
-        goto bail_lock;
-    }
-
-    if ((void *) (buf = (char *)
-                  mmap(NULL, st.st_size + shiftdata,
-                       PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) ==
-        MAP_FAILED) {
-        goto bail_lock;
-    }
-
-    /* last place for failure. */
-    if (sys_ftruncate(fd, st.st_size + shiftdata) < 0) {
-        munmap(buf, st.st_size + shiftdata);
-        goto bail_lock;
-    }
+    u_int16_t           ashort;
+    struct stat         st;
 
-    /* move the RFORK. this assumes that the RFORK is at the end */
-    if (off) {
-        memmove(buf + ADEDOFF_RFORK_V2, buf + off, ad->ad_eid[ADEID_RFORK].ade_len);
+    ad->ad_magic = AD_MAGIC;
+    ad->ad_version = ad->ad_flags & 0x0f0000;
+    if (!ad->ad_version) {
+        ad->ad_version = AD_VERSION;
     }
 
-    munmap(buf, st.st_size + shiftdata);
 
-    /* now, fix up our copy of the header */
-    memset(ad->ad_filler, 0, sizeof(ad->ad_filler));
+    memset(ad->ad_data, 0, sizeof(ad->ad_data));
 
-    /* save the header entries */
-    eid = entry_order2;
-    while (eid->id) {
-        if( ad->ad_eid[eid->id].ade_off != 0) {
-            if ( eid->id > 2 && ad->ad_eid[eid->id].ade_len < 256)
-                memcpy( databuf[eid->id], ad->ad_data +ad->ad_eid[eid->id].ade_off, ad->ad_eid[eid->id].ade_len);
-            entry_len[eid->id] = ad->ad_eid[eid->id].ade_len;
-        }
-        eid++;
+    if (ad->ad_flags == AD_VERSION2)
+        eid = entry_order2;
+    else if (ad->ad_flags == AD_VERSION_EA)
+        eid = entry_order_ea;
+    else {
+        return -1;
     }
 
-    memset(ad->ad_data + AD_HEADER_LEN, 0, AD_DATASZ - AD_HEADER_LEN);
-
-    /* copy the saved entries to the new header */
-    eid = entry_order2;
     while (eid->id) {
-        if ( eid->id > 2 && entry_len[eid->id] > 0) {
-            memcpy(ad->ad_data+eid->offset, databuf[eid->id], entry_len[eid->id]);
-        }
         ad->ad_eid[eid->id].ade_off = eid->offset;
-        ad->ad_eid[eid->id].ade_len = entry_len[eid->id];
+        ad->ad_eid[eid->id].ade_len = eid->len;
         eid++;
     }
 
-    /* rebuild the header and cleanup */
-    LOG(log_debug, logtype_default, "updated AD2 header %s", path);
-    ad_flush(ad );
-    ret = 0;
-
-bail_lock:
-    ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
-bail_err:
-    return ret;
-}
-
-/* ------------------------------------------
-   FIXME work only if < 2GB
-*/
-static int ad_convert(struct adouble *ad, const char *path)
-{
-    struct stat st;
-    u_int16_t attr;
-    char *buf;
-    int fd, off;
-    int ret = -1;
-    /* use resource fork offset from file */
-    int shiftdata;
-    int toV2;
-    int toV1;
-
-    if (!path) {
-        return 0;
-    }
-
-    if (!(ad->ad_md->adf_flags & ( O_RDWR))) {
-        /* we were unable to open the file read write the last time */
-        return 0;
-    }
-
-    /* check to see if we should convert this header. */
-    toV2 = ad->ad_version == AD_VERSION1 && ad->ad_flags == AD_VERSION2;
-    toV1 = ad->ad_version == AD_VERSION2 && ad->ad_flags == AD_VERSION1;
-
-    if (!toV2 && !toV1)
-        return 0;
-
-    /* convert from v1 to v2. what does this mean?
-     *  1) change FILEI into FILEDATESI
-     *  2) create space for SHORTNAME, AFPFILEI, DID, and PRODOSI
-     *  3) move FILEI attributes into AFPFILEI
-     *  4) initialize ACCESS field of FILEDATESI.
-     *  5) move the resource fork
-     */
-
-    /* bail if we can't get a lock */
-    if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0, 0) < 0)
-        goto bail_err;
-
-    /* we reuse fd from the resource fork */
-    fd = ad->ad_md->adf_fd;
-
-    if (ad->ad_eid[ADEID_RFORK].ade_off) {
-        shiftdata = ADEDOFF_RFORK_V2 -ad->ad_eid[ADEID_RFORK].ade_off;
-    }
-    else {
-        shiftdata = ADEDOFF_RFORK_V2 -ADEDOFF_RFORK_V1; /* 136 */
-    }
-
-    if (fstat(fd, &st)) {
-        goto bail_lock;
-    }
-
-    if (st.st_size > 0x7fffffff -shiftdata) {
-        LOG(log_debug, logtype_default, "ad_v1tov2: file too big.");
-        errno = EIO;
-        goto bail_lock;
-    }
-
-    off = ad->ad_eid[ADEID_RFORK].ade_off;
-
-    if (off > st.st_size) {
-        LOG(log_error, logtype_default, "ad_v1tov2: invalid resource fork offset. (off: %u)", off);
-        errno = EIO;
-        goto bail_lock;
-    }
-
-    if (ad->ad_eid[ADEID_RFORK].ade_len > st.st_size - off) {
-        LOG(log_error, logtype_default, "ad_v1tov2: invalid resource fork length. (rfork len: %u)", ad->ad_eid[ADEID_RFORK].ade_len);
-        errno = EIO;
-        goto bail_lock;
-    }
-
-    if ((void *) (buf = (char *)
-                  mmap(NULL, st.st_size + shiftdata,
-                       PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) ==
-        MAP_FAILED) {
-        goto bail_lock;
+    /* put something sane in the directory finderinfo */
+    if ((adflags & ADFLAGS_DIR)) {
+        /* set default view */
+        ashort = htons(FINDERINFO_CLOSEDVIEW);
+        memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
+    } else {
+        /* set default creator/type fields */
+        memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,"\0\0\0\0", 4);
+        memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,"\0\0\0\0", 4);
     }
 
-    /* last place for failure. */
-
-    if (sys_ftruncate(fd, st.st_size + shiftdata) < 0) {
-        goto bail_lock;
+    /* make things invisible */
+    if ((ad->ad_options & ADVOL_INVDOTS) && (*path == '.')) {
+        ashort = htons(ATTRBIT_INVISIBLE);
+        ad_setattr(ad, ashort);
+        ashort = htons(FINDERINFO_INVISIBLE);
+        memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
     }
 
-    /* move the RFORK. this assumes that the RFORK is at the end */
-    if (off) {
-        memmove(buf + ADEDOFF_RFORK_V2, buf + off, ad->ad_eid[ADEID_RFORK].ade_len);
-    }
+    if (lstat(path, &st) < 0)
+        return -1;
 
-    munmap(buf, st.st_size + shiftdata);
-
-    /* now, fix up our copy of the header */
-    memset(ad->ad_filler, 0, sizeof(ad->ad_filler));
-
-    /* replace FILEI with FILEDATESI */
-    ad_getattr(ad, &attr);
-    ad->ad_eid[ADEID_FILEDATESI].ade_off = ADEDOFF_FILEDATESI;
-    ad->ad_eid[ADEID_FILEDATESI].ade_len = ADEDLEN_FILEDATESI;
-    ad->ad_eid[ADEID_FILEI].ade_off = 0;
-    ad->ad_eid[ADEID_FILEI].ade_len = 0;
-
-    /* add in the new entries */
-    ad->ad_eid[ADEID_DID].ade_off = ADEDOFF_DID;
-    ad->ad_eid[ADEID_DID].ade_len = ADEDLEN_DID;
-    ad->ad_eid[ADEID_AFPFILEI].ade_off = ADEDOFF_AFPFILEI;
-    ad->ad_eid[ADEID_AFPFILEI].ade_len = ADEDLEN_AFPFILEI;
-    ad->ad_eid[ADEID_SHORTNAME].ade_off = ADEDOFF_SHORTNAME;
-    ad->ad_eid[ADEID_SHORTNAME].ade_len = ADEDLEN_INIT;
-    ad->ad_eid[ADEID_PRODOSFILEI].ade_off = ADEDOFF_PRODOSFILEI;
-    ad->ad_eid[ADEID_PRODOSFILEI].ade_len = ADEDLEN_PRODOSFILEI;
-
-    ad->ad_eid[ADEID_PRIVDEV].ade_off = ADEDOFF_PRIVDEV;
-    ad->ad_eid[ADEID_PRIVDEV].ade_len = ADEDLEN_INIT;
-    ad->ad_eid[ADEID_PRIVINO].ade_off = ADEDOFF_PRIVINO;
-    ad->ad_eid[ADEID_PRIVINO].ade_len = ADEDLEN_INIT;
-    ad->ad_eid[ADEID_PRIVSYN].ade_off = ADEDOFF_PRIVSYN;
-    ad->ad_eid[ADEID_PRIVSYN].ade_len = ADEDLEN_INIT;
-    ad->ad_eid[ADEID_PRIVID].ade_off  = ADEDOFF_PRIVID;
-    ad->ad_eid[ADEID_PRIVID].ade_len =  ADEDLEN_INIT;
-
-    /* shift the old entries (NAME, COMMENT, FINDERI, RFORK) */
-    ad->ad_eid[ADEID_NAME].ade_off = ADEDOFF_NAME_V2;
-    ad->ad_eid[ADEID_COMMENT].ade_off = ADEDOFF_COMMENT_V2;
-    ad->ad_eid[ADEID_FINDERI].ade_off = ADEDOFF_FINDERI_V2;
-    ad->ad_eid[ADEID_RFORK].ade_off = ADEDOFF_RFORK_V2;
-
-    /* switch to dest version */
-    ad->ad_version = (toV2)?AD_VERSION2:AD_VERSION1;
-
-    /* move our data buffer to make space for the new entries. */
-    memmove(ad->ad_data + ADEDOFF_NAME_V2, ad->ad_data + ADEDOFF_NAME_V1,
-            ADEDOFF_RFORK_V1 - ADEDOFF_NAME_V1);
-
-    /* now, fill in the space with appropriate stuff. we're
-       operating as a v2 file now. */
+    /* put something sane in the date fields */
+    ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, st.st_mtime);
+    ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, st.st_mtime);
     ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, st.st_mtime);
-    memset(ad_entry(ad, ADEID_DID), 0, ADEDLEN_DID);
-    memset(ad_entry(ad, ADEID_AFPFILEI), 0, ADEDLEN_AFPFILEI);
-    ad_setattr(ad, attr);
-    memset(ad_entry(ad, ADEID_SHORTNAME), 0, ADEDLEN_SHORTNAME);
-    memset(ad_entry(ad, ADEID_PRODOSFILEI), 0, ADEDLEN_PRODOSFILEI);
-
-    /* rebuild the header and cleanup */
-    ad_flush(ad );
-    ret = 0;
-
-bail_lock:
-    ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
-bail_err:
-    return ret;
+    ad_setdate(ad, AD_DATE_BACKUP, AD_DATE_START);
+    return 0;
 }
-#endif /* AD_VERSION == AD_VERSION2 */
 
 /* -------------------------------------
    read in the entries
 */
-static void parse_entries(struct adouble *ad, char *buf,
-                          u_int16_t nentries)
+static void parse_entries(struct adouble *ad, char *buf, uint16_t nentries)
 {
-    u_int32_t   eid, len, off;
-    int         warning = 0;
+    uint32_t   eid, len, off;
+    int        warning = 0;
 
     /* now, read in the entry bits */
     for (; nentries > 0; nentries-- ) {
         memcpy(&eid, buf, sizeof( eid ));
-        eid = DISK_EID(ad, ntohl( eid ));
+        eid = get_eid(ntohl(eid));
         buf += sizeof( eid );
         memcpy(&off, buf, sizeof( off ));
         off = ntohl( off );
@@ -511,18 +281,16 @@ static void parse_entries(struct adouble *ad, char *buf,
         buf += sizeof( len );
 
         if (eid && eid < ADEID_MAX && off < sizeof(ad->ad_data) &&
-            (off +len <= sizeof(ad->ad_data) || eid == ADEID_RFORK)) {
+            (off + len <= sizeof(ad->ad_data) || eid == ADEID_RFORK)) {
             ad->ad_eid[ eid ].ade_off = off;
             ad->ad_eid[ eid ].ade_len = len;
         } else if (!warning) {
             warning = 1;
-            LOG(log_debug, logtype_default, "ad_refresh: nentries %hd  eid %d",
-                nentries, eid );
+            LOG(log_warning, logtype_default, "parse_entries: bogus eid: %d", eid);
         }
     }
 }
 
-
 /* this reads enough of the header so that we can figure out all of
  * the entry lengths and offsets. once that's done, we just read/mmap
  * the rest of the header in.
@@ -536,7 +304,6 @@ static int ad_header_read(struct adouble *ad, struct stat *hst)
     u_int16_t           nentries;
     int                 len;
     ssize_t             header_len;
-    static int          warning = 0;
     struct stat         st;
 
     /* read the header */
@@ -550,42 +317,15 @@ static int ad_header_read(struct adouble *ad, struct stat *hst)
 
     memcpy(&ad->ad_magic, buf, sizeof( ad->ad_magic ));
     memcpy(&ad->ad_version, buf + ADEDOFF_VERSION, sizeof( ad->ad_version ));
+    ad->ad_magic = ntohl( ad->ad_magic );
+    ad->ad_version = ntohl( ad->ad_version );
 
-    /* tag broken v1 headers. just assume they're all right.
-     * we detect two cases: null magic/version
-     *                      byte swapped magic/version
-     * XXX: in the future, you'll need the v1compat flag.
-     * (ad->ad_flags & ADFLAGS_V1COMPAT) */
-    if (!ad->ad_magic && !ad->ad_version) {
-        if (!warning) {
-            LOG(log_debug, logtype_default, "notice: fixing up null v1 magic/version.");
-            warning++;
-        }
-        ad->ad_magic = AD_MAGIC;
-        ad->ad_version = AD_VERSION1;
-
-    } else if (ad->ad_magic == AD_MAGIC && ad->ad_version == AD_VERSION1) {
-        if (!warning) {
-            LOG(log_debug, logtype_default, "notice: fixing up byte-swapped v1 magic/version.");
-            warning++;
-        }
-
-    } else {
-        ad->ad_magic = ntohl( ad->ad_magic );
-        ad->ad_version = ntohl( ad->ad_version );
-    }
-
-    if ((ad->ad_magic != AD_MAGIC) || ((ad->ad_version != AD_VERSION1)
-#if AD_VERSION == AD_VERSION2
-                                       && (ad->ad_version != AD_VERSION2)
-#endif /* AD_VERSION == AD_VERSION2 */
-            )) {
-        LOG(log_debug, logtype_default, "ad_open: can't parse AppleDouble header.");
+    if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION2)) {
+        LOG(log_error, logtype_default, "ad_open: can't parse AppleDouble header.");
         errno = EIO;
         return -1;
     }
 
-    memcpy(ad->ad_filler, buf + ADEDOFF_FILLER, sizeof( ad->ad_filler ));
     memcpy(&nentries, buf + ADEDOFF_NENTRIES, sizeof( nentries ));
     nentries = ntohs( nentries );
 
@@ -598,7 +338,7 @@ static int ad_header_read(struct adouble *ad, struct stat *hst)
 
     buf += AD_HEADER_LEN;
     if (len > header_len - AD_HEADER_LEN) {
-        LOG(log_debug, logtype_default, "ad_header_read: can't read entry info.");
+        LOG(log_error, logtype_default, "ad_header_read: can't read entry info.");
         errno = EIO;
         return -1;
     }
@@ -610,13 +350,13 @@ static int ad_header_read(struct adouble *ad, struct stat *hst)
     if (!ad_getentryoff(ad, ADEID_RFORK)
         || (ad_getentryoff(ad, ADEID_RFORK) > sizeof(ad->ad_data))
         ) {
-        LOG(log_debug, logtype_default, "ad_header_read: problem with rfork entry offset.");
+        LOG(log_error, logtype_default, "ad_header_read: problem with rfork entry offset.");
         errno = EIO;
         return -1;
     }
 
     if (ad_getentryoff(ad, ADEID_RFORK) > header_len) {
-        LOG(log_debug, logtype_default, "ad_header_read: can't read in entries.");
+        LOG(log_error, logtype_default, "ad_header_read: can't read in entries.");
         errno = EIO;
         return -1;
     }
@@ -627,320 +367,485 @@ static int ad_header_read(struct adouble *ad, struct stat *hst)
             return 1; /* fail silently */
         }
     }
-    ad->ad_rlen = hst->st_size - ad_getentryoff(ad, ADEID_RFORK);
 
-    /* fix up broken dates */
-    if (ad->ad_version == AD_VERSION1) {
-        u_int32_t aint;
-
-        /* check to see if the ad date is wrong. just see if we have
-         * a modification date in the future. */
-        if (((ad_getdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, &aint)) == 0) &&
-            (aint > TIMEWARP_DELTA + hst->st_mtime)) {
-            ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, aint - AD_DATE_DELTA);
-            ad_getdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, &aint);
-            ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, aint - AD_DATE_DELTA);
-            ad_getdate(ad, AD_DATE_BACKUP | AD_DATE_UNIX, &aint);
-            ad_setdate(ad, AD_DATE_BACKUP | AD_DATE_UNIX, aint - AD_DATE_DELTA);
-        }
-    }
+    ad->ad_rlen = hst->st_size - ad_getentryoff(ad, ADEID_RFORK);
 
     return 0;
 }
 
-/* ---------------------------
-   SFM structure
-*/
-#if 0
-typedef struct {
-    byte    afpi_Signature[4];      /* Must be 0x00504641 */
-    byte    afpi_Version[4];        /* Must be 0x00010000 */
-    byte    afpi_Reserved1[4];
-    byte    afpi_BackupTime[4];     /* Backup time for the file/dir */
-    byte    finderinfo[32];         /* Finder info */
-    byte    afpi_ProDosInfo[6];     /* ProDos Info */
-    byte    afpi_Reserved2[6];
-} sfm_info;
-#endif
-
-static int ad_header_sfm_read(struct adouble *ad, struct stat *hst)
+static int ad_header_read_ea(struct adouble *ad, struct stat *hst _U_)
 {
-    char                *buf = ad->ad_data;
-    const struct entry  *eid;
-    ssize_t             header_len;
-    struct stat         st;
+    uint16_t nentries;
+    int      len;
+    ssize_t  header_len;
+    char     *buf = ad->ad_data;
 
     /* read the header */
-    if ((header_len = adf_pread( ad->ad_md, buf, sizeof(ad->ad_data), 0)) < 0) {
+    if ((header_len = sys_fgetxattr(ad->ad_md->adf_fd, AD_EA_META, ad->ad_data, AD_DATASZ_EA)) < 1) {
+        LOG(log_debug, logtype_default, "ad_header_read_ea: %s (%u)", strerror(errno), errno);
         return -1;
     }
-    if (header_len != AD_SFM_LEN) {
+
+    if (header_len < AD_HEADER_LEN) {
+        LOG(log_error, logtype_default, "ad_header_read_ea: bogus AppleDouble header.");
         errno = EIO;
         return -1;
     }
 
     memcpy(&ad->ad_magic, buf, sizeof( ad->ad_magic ));
-    memcpy(&ad->ad_version, buf + 4, sizeof( ad->ad_version ));
+    memcpy(&ad->ad_version, buf + ADEDOFF_VERSION, sizeof( ad->ad_version ));
 
-    /* FIXME in the great Microsoft tradition they aren't in network order */
-#if 0
-    if (ad->ad_magic == SFM_MAGIC && ad->ad_version == AD_VERSION1) {
-        static int          warning = 0;
-        if (!warning) {
-            LOG(log_debug, logtype_default, "notice: fixing up byte-swapped v1 magic/version.");
-            warning++;
-        }
+    ad->ad_magic = ntohl( ad->ad_magic );
+    ad->ad_version = ntohl( ad->ad_version );
 
-    } else {
-        ad->ad_magic = ntohl( ad->ad_magic );
-        ad->ad_version = ntohl( ad->ad_version );
-    }
-#endif
-    if ((ad->ad_magic != SFM_MAGIC) || ((ad->ad_version != AD_VERSION1) )) {
+    if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION2)) {
+        LOG(log_error, logtype_default, "ad_header_read_ea: wrong magic or version");
         errno = EIO;
-        LOG(log_debug, logtype_default, "ad_header_sfm_read: can't parse AppleDouble header.");
         return -1;
     }
 
-    /* reinit adouble table */
-    eid = entry_order_sfm;
-    while (eid->id) {
-        ad->ad_eid[eid->id].ade_off = eid->offset;
-        ad->ad_eid[eid->id].ade_len = eid->len;
-        eid++;
-    }
-
-    /* steal some prodos for attribute */
-    {
+    memcpy(&nentries, buf + ADEDOFF_NENTRIES, sizeof( nentries ));
+    nentries = ntohs( nentries );
 
-        u_int16_t attribute;
-        memcpy(&attribute, buf + 48 +4, sizeof(attribute));
-        ad_setattr(ad, attribute );
+    /* Protect against bogus nentries */
+    len = nentries * AD_ENTRY_LEN;
+    if (len + AD_HEADER_LEN > sizeof(ad->ad_data))
+        len = sizeof(ad->ad_data) - AD_HEADER_LEN;
+    if (len > header_len - AD_HEADER_LEN) {
+        LOG(log_error, logtype_default, "ad_header_read_ea: can't read entry info.");
+        errno = EIO;
+        return -1;
     }
+    nentries = len / AD_ENTRY_LEN;
 
-    if (ad->ad_resource_fork.adf_fd != -1) {
-        /* we have a resource fork use it rather than the metadata */
-        if (fstat(ad->ad_resource_fork.adf_fd, &st) < 0) {
-            /* XXX set to zero ?
-               ad->ad_rlen =  0;
-            */
-            return 1;
-        }
-        ad->ad_rlen = st.st_size;
-        hst = &st;
-    }
-    else if (hst == NULL) {
-        hst = &st;
-        if (fstat(ad->ad_md->adf_fd, &st) < 0) {
-            return 1; /* fail silently */
-        }
-    }
+    /* Now parse entries */
+    parse_entries(ad, buf + AD_HEADER_LEN, nentries);
+    return 0;
+}
 
-    /* fix up broken dates */
-    if (ad->ad_version == AD_VERSION1) {
-        u_int32_t aint;
-
-        /* check to see if the ad date is wrong. just see if we have
-         * a modification date in the future. */
-        if (((ad_getdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, &aint)) == 0) &&
-            (aint > TIMEWARP_DELTA + hst->st_mtime)) {
-            ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, aint - AD_DATE_DELTA);
-            ad_getdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, &aint);
-            ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, aint - AD_DATE_DELTA);
-            ad_getdate(ad, AD_DATE_BACKUP | AD_DATE_UNIX, &aint);
-            ad_setdate(ad, AD_DATE_BACKUP | AD_DATE_UNIX, aint - AD_DATE_DELTA);
-        }
+static int ad_mkrf(char *path)
+{
+    char *slash;
+    /*
+     * Probably .AppleDouble doesn't exist, try to mkdir it.
+     */
+    if (NULL == ( slash = strrchr( path, '/' )) ) {
+        return -1;
     }
-
+    *slash = '\0';
+    errno = 0;
+    if ( ad_mkdir( path, 0777 ) < 0 ) {
+        return -1;
+    }
+    *slash = '/';
     return 0;
 }
 
-/* ---------------------------------------
- * Put the .AppleDouble where it needs to be:
- *
- *      /   a/.AppleDouble/b
- *  a/b
- *      \   b/.AppleDouble/.Parent
- *
- * FIXME: should do something for pathname > MAXPATHLEN
- */
-char *
-ad_path( const char *path, int adflags)
+static int ad_mkrf_ea(char *path _U_)
 {
-    static char pathbuf[ MAXPATHLEN + 1];
-    const char *slash;
-    size_t  l ;
+    AFP_PANIC("ad_mkrf_ea: dont use");
+    return 0;
+}
 
-    if ( adflags & ADFLAGS_DIR ) {
-        l = strlcpy( pathbuf, path, sizeof(pathbuf));
+/* ----------------
+   if we are root change path user/ group
+   It can be a native function for BSD cf. FAQ.Q10
+   path:  pathname to chown
+   stbuf: parent directory inode
 
-        if ( l && l < MAXPATHLEN) {
-            pathbuf[l++] = '/';
-        }
-        strlcpy(pathbuf +l, ".AppleDouble/.Parent", sizeof(pathbuf) -l);
-    } else {
-        if (NULL != ( slash = strrchr( path, '/' )) ) {
-            slash++;
-            l = slash - path;
-            /* XXX we must return NULL here and test in the caller */
-            if (l > MAXPATHLEN)
-                l = MAXPATHLEN;
-            memcpy( pathbuf, path, l);
-        } else {
-            l = 0;
-            slash = path;
-        }
-        l += strlcpy( pathbuf +l, ".AppleDouble/", sizeof(pathbuf) -l);
-        strlcpy( pathbuf + l, slash, sizeof(pathbuf) -l);
-    }
+   use fstat and fchown or lchown with linux?
+*/
+#define EMULATE_SUIDDIR
 
-    return( pathbuf );
+static int ad_chown(const char *path, struct stat *stbuf)
+{
+    int ret = 0;
+#ifdef EMULATE_SUIDDIR
+    uid_t id;
+
+    if (default_uid != (uid_t)-1) {
+        /* we are root (admin) */
+        id = (default_uid)?default_uid:stbuf->st_uid;
+        ret = lchown( path, id, stbuf->st_gid );
+    }
+#endif
+    return ret;
 }
 
-/* -------------------- */
-static int ad_mkrf(char *path)
+#define DEFMASK 07700   /* be conservative */
+
+/* ----------------
+   return access right and inode of path parent directory
+*/
+static int ad_mode_st(const char *path, int *mode, struct stat *stbuf)
 {
-    char *slash;
-    /*
-     * Probably .AppleDouble doesn't exist, try to mkdir it.
-     */
-    if (NULL == ( slash = strrchr( path, '/' )) ) {
+    if (*mode == 0) {
         return -1;
     }
-    *slash = '\0';
-    errno = 0;
-    if ( ad_mkdir( path, 0777 ) < 0 ) {
+    if (ad_stat(path, stbuf) != 0) {
+        *mode &= DEFMASK;
         return -1;
     }
-    *slash = '/';
+    *mode &= stbuf->st_mode;
     return 0;
 }
 
-/* ---------------------------------------
- * Put the resource fork where it needs to be:
- * ._name
- */
-char *
-ad_path_osx(const char *path, int adflags _U_)
+/* ----------------- */
+static int ad_error(struct adouble *ad, int adflags)
 {
-    static char pathbuf[ MAXPATHLEN + 1];
-    char    c, *slash, buf[MAXPATHLEN + 1];
+    int err = errno;
+    if ((adflags & ADFLAGS_NOHF)) {
+        /* FIXME double check : set header offset ?*/
+        return 0;
+    }
+    if ((adflags & ADFLAGS_DF)) {
+        ad_close( ad, ADFLAGS_DF );
+        err = errno;
+    }
+    return -1 ;
+}
+
+/* --------------------------- */
+static int ad_header_upgrade(struct adouble *ad _U_, char *name _U_)
+{
+    return 0;
+}
+
+static int ad_header_upgrade_ea(struct adouble *ad _U_, char *name _U_)
+{
+    AFP_PANIC("ad_header_upgrade_ea: dont use");
+    return 0;
+}
 
-    if (!strcmp(path,".")) {
-        /* fixme */
-        getcwd(buf, MAXPATHLEN);
+static int ad_open_df(const char *path, int adflags, int oflags, int mode, struct adouble *ad)
+{
+    struct stat st_dir;
+    int         hoflags, admode;
+    int         st_invalid = -1;
+
+    LOG(log_maxdebug, logtype_default, "ad_open_df(\"%s/%s\", adf: 0x%04x, of: 0x%04x)",
+        getcwdpath(), path, adflags, oflags);
+
+    if (ad_data_fileno(ad) == -1) {
+        hoflags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
+        admode = mode;
+        if ((oflags & O_CREAT)) {
+            st_invalid = ad_mode_st(path, &admode, &st_dir);
+            if ((ad->ad_options & ADVOL_UNIXPRIV)) {
+                admode = mode;
+            }
+        }
+
+        ad->ad_data_fork.adf_fd = open(path, hoflags | O_NOFOLLOW, admode);
+
+        if (ad->ad_data_fork.adf_fd == -1) {
+            if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
+                hoflags = oflags;
+                ad->ad_data_fork.adf_fd = open( path, hoflags | O_NOFOLLOW, admode );
+            }
+            if (ad->ad_data_fork.adf_fd == -1 && errno == OPEN_NOFOLLOW_ERRNO) {
+                int lsz;
+
+                ad->ad_data_fork.adf_syml = malloc(MAXPATHLEN+1);
+                lsz = readlink(path, ad->ad_data_fork.adf_syml, MAXPATHLEN);
+                if (lsz <= 0) {
+                    free(ad->ad_data_fork.adf_syml);
+                    return -1;
+                }
+                ad->ad_data_fork.adf_syml[lsz] = 0;
+                ad->ad_data_fork.adf_fd = -2; /* -2 means its a symlink */
+            }
+        }
+
+        if ( ad->ad_data_fork.adf_fd == -1 )
+            return -1;
+
+        AD_SET(ad->ad_data_fork.adf_off);
+        ad->ad_data_fork.adf_flags = hoflags;
+        if (!st_invalid) {
+            /* just created, set owner if admin (root) */
+            ad_chown(path, &st_dir);
+        }
+        adf_lock_init(&ad->ad_data_fork);
+    } else {
+        /* the file is already open... but */
+        if ((oflags & ( O_RDWR | O_WRONLY))
+            /* we want write access */
+            && !(ad->ad_data_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
+            /* and it was denied the first time */
+            errno = EACCES;
+            return -1;
+        }
+        /* FIXME
+         * for now ad_open is never called with O_TRUNC or O_EXCL if the file is
+         * already open. Should we check for it? ie
+         * O_EXCL --> error
+         * O_TRUNC --> truncate the fork.
+         * idem for ressource fork.
+         */
     }
-    else {
-        strlcpy(buf, path, MAXPATHLEN +1);
+    ad->ad_data_fork.adf_refcount++;
+
+    return 0;
+}
+
+static int ad_open_hf_v2(const char *path, int adflags, int oflags, int mode, struct adouble *ad)
+{
+    struct stat st_dir;
+    struct stat st_meta;
+    struct stat *pst = NULL;
+    char        *ad_p;
+    int         hoflags, admode;
+    int         st_invalid = -1;
+
+    ad_p = ad->ad_ops->ad_path( path, adflags );
+
+    hoflags = oflags & ~(O_CREAT | O_EXCL);
+    if (!(adflags & ADFLAGS_RDONLY)) {
+        hoflags = (hoflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
     }
-    if (NULL != ( slash = strrchr( buf, '/' )) ) {
-        c = *++slash;
-        *slash = '\0';
-        strlcpy( pathbuf, buf, MAXPATHLEN +1);
-        *slash = c;
+    ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 );
+    if (ad->ad_md->adf_fd < 0 ) {
+        if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
+            hoflags = oflags & ~(O_CREAT | O_EXCL);
+            ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 );
+        }
+    }
+
+    if ( ad->ad_md->adf_fd < 0 ) {
+        if (errno == ENOENT && (oflags & O_CREAT) ) {
+            /*
+             * We're expecting to create a new adouble header file here
+             * if ((oflags & O_CREAT) ==> (oflags & O_RDWR)
+             */
+            LOG(log_debug, logtype_default, "ad_open(\"%s/%s\"): creating adouble file",
+                getcwdpath(), ad_p);
+            admode = mode;
+            errno = 0;
+            st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
+            if ((ad->ad_options & ADVOL_UNIXPRIV)) {
+                admode = mode;
+            }
+            admode = ad_hf_mode(admode);
+            if ((errno == ENOENT)) {
+                if (ad->ad_ops->ad_mkrf( ad_p) < 0) {
+                    return ad_error(ad, adflags);
+                }
+                admode = mode;
+                st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
+                if ((ad->ad_options & ADVOL_UNIXPRIV)) {
+                    admode = mode;
+                }
+                admode = ad_hf_mode(admode);
+            }
+            /* retry with O_CREAT */
+            ad->ad_md->adf_fd = open( ad_p, oflags,admode );
+            if ( ad->ad_md->adf_fd < 0 ) {
+                return ad_error(ad, adflags);
+            }
+            ad->ad_md->adf_flags = oflags;
+            /* just created, set owner if admin owner (root) */
+            if (!st_invalid) {
+                ad_chown(ad_p, &st_dir);
+            }
+        } else {
+            return ad_error(ad, adflags);
+        }
     } else {
-        pathbuf[ 0 ] = '\0';
-        slash = buf;
+        ad->ad_md->adf_flags = hoflags;
+        if (fstat(ad->ad_md->adf_fd, &st_meta) == 0 && st_meta.st_size == 0) {
+            /* for 0 length files, treat them as new. */
+            ad->ad_md->adf_flags |= O_TRUNC;
+        } else {
+            /* we have valid data in st_meta stat structure, reused it in ad_header_read */
+            pst = &st_meta;
+        }
+    }
+    AD_SET(ad->ad_md->adf_off);
+
+    if ((ad->ad_md->adf_flags & ( O_TRUNC | O_CREAT ))) {
+        /* This is a new adouble header file, create it */
+        if (new_ad_header(path, ad, adflags) < 0) {
+            int err = errno;
+            /* the file is already deleted, perm, whatever, so return an error */
+            ad_close(ad, adflags);
+            errno = err;
+            return -1;
+        }
+        ad_flush(ad);
+    } else {
+        /* Read the adouble header in and parse it.*/
+        if (ad->ad_ops->ad_header_read( ad , pst) < 0
+            || ad->ad_ops->ad_header_upgrade(ad, ad_p) < 0) {
+            int err = errno;
+            ad_close( ad, adflags );
+            errno = err;
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int ad_open_hf_ea(const char *path, int adflags, int oflags, int mode, struct adouble *ad)
+{
+    ssize_t rforklen;
+    int ret;
+    int err;
+
+    LOG(log_maxdebug, logtype_default, "ad_open_hf_ea(\"%s/%s\", adf: 0x%04x, of: 0x%04x)",
+        getcwdpath(), path, adflags, oflags);
+
+    if ((ad->ad_md->adf_fd = open(path, O_RDONLY | O_NOFOLLOW)) == -1)
+        return -1;
+
+    /* Read the adouble header in and parse it.*/
+    if (ad->ad_ops->ad_header_read(ad, NULL) != 0) {
+        if (!(oflags & O_CREAT)) {
+            err = errno;
+            ad_close(ad, adflags);
+            errno = err;
+            return -1;
+        }
+
+        /* It doesnt exist, EPERM or another error */
+        if (errno != ENOATTR && errno != ENOENT) {
+            LOG(log_error, logtype_default, "ad_open_hf_ea: unexpected: %s", strerror(errno));
+            ret = -1;
+            goto error;
+        }
+
+        /* Create one */
+        if (new_ad_header(path, ad, adflags) < 0) {
+            LOG(log_error, logtype_default, "ad_open_hf_ea: can't create new header: %s/%s",
+                getcwdpath(), path);
+            ret = -1;
+            goto error;
+        }
+
+        ad_flush(ad);
     }
-    strlcat( pathbuf, "._", MAXPATHLEN  +1);
-    strlcat( pathbuf, slash, MAXPATHLEN +1);
-    return pathbuf;
+
+    ad->ad_md->adf_flags = O_RDWR; /* Pretend its rw, in fact for the EA API it is */
+
+    if ((rforklen = sys_fgetxattr(ad->ad_md->adf_fd, AD_EA_RESO, NULL, 0)) > 0)
+        ad->ad_rlen = rforklen;
+
+    return 0;
+
+error:
+    err = errno;
+    ad_close(ad, adflags);
+    errno = err;
+    return ret;
 }
-/* -------------------- */
-static int ad_mkrf_osx(char *path _U_)
+
+static int ad_open_hf(const char *path, int adflags, int oflags, int mode, struct adouble *ad)
+{
+    int ret = 0;
+
+    LOG(log_maxdebug, logtype_default, "ad_open_hf(\"%s/%s\", adf: 0x%04x, of: 0x%04x)",
+        getcwdpath(), path, adflags, oflags);
+
+    if (ad_meta_fileno(ad) != -1) { /* the file is already open */
+        LOG(log_maxdebug, logtype_default,"the file is already open");
+        if ((oflags & ( O_RDWR | O_WRONLY))
+            && !(ad->ad_md->adf_flags & ( O_RDWR | O_WRONLY))) {
+            if ((adflags & ADFLAGS_HF) && ad->ad_data_fork.adf_refcount)
+                /* We just have openend the df, so we have to close it now */
+                ad_close(ad, ADFLAGS_DF);
+            errno = EACCES;
+            return -1;
+        }
+        ad_refresh(ad);
+        /* it's not new anymore */
+        ad->ad_md->adf_flags &= ~( O_TRUNC | O_CREAT );
+        ad->ad_md->adf_refcount++;
+        return 0;
+    }
+
+    memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
+    ad->ad_rlen = 0;
+    adf_lock_init(ad->ad_md);
+
+    switch (ad->ad_flags) {
+    case AD_VERSION2:
+        ret = ad_open_hf_v2(path, adflags, oflags, mode, ad);
+        break;
+    case AD_VERSION_EA:
+        ret = ad_open_hf_ea(path, adflags, oflags, mode, ad);
+        break;
+    default:
+        ret = -1;
+        break;
+    }
+
+    ad->ad_md->adf_refcount = 1;
+
+    return ret;
+}
+
+static int ad_open_rf(const char *path, int adflags, int oflags, int mode, struct adouble *ad)
 {
     return 0;
 }
 
-/* ---------------------------------------
+/***********************************************************************************
+ * API functions
+ ********************************************************************************* */
+
+char *ad_path_ea( const char *path, int adflags _U_)
+{
+    return path;
+}
+
+/*
  * Put the .AppleDouble where it needs to be:
  *
- *      /   a/.AppleDouble/b/AFP_AfpInfo
+ *      /   a/.AppleDouble/b
  *  a/b
- *      \   b/.AppleDouble/.Parent/AFP_AfpInfo
+ *      \   b/.AppleDouble/.Parent
  *
+ * FIXME: should do something for pathname > MAXPATHLEN
  */
-char *
-ad_path_sfm( const char *path, int adflags)
+char *ad_path( const char *path, int adflags)
 {
     static char pathbuf[ MAXPATHLEN + 1];
-    char    c, *slash, buf[MAXPATHLEN + 1];
-    size_t      l;
+    const char *slash;
+    size_t  ;
 
-    l = strlcpy(buf, path, MAXPATHLEN +1);
     if ( adflags & ADFLAGS_DIR ) {
-        strcpy( pathbuf, buf);
-        if ( *buf != '\0' && l < MAXPATHLEN) {
+        l = strlcpy( pathbuf, path, sizeof(pathbuf));
+
+        if ( l && l < MAXPATHLEN) {
             pathbuf[l++] = '/';
-            pathbuf[l] = 0;
         }
-        slash = ".Parent";
+        strlcpy(pathbuf +l, ".AppleDouble/.Parent", sizeof(pathbuf) -l);
     } else {
-        if (NULL != ( slash = strrchr( buf, '/' )) ) {
-            c = *++slash;
-            *slash = '\0';
-            strcpy( pathbuf, buf);
-            *slash = c;
+        if (NULL != ( slash = strrchr( path, '/' )) ) {
+            slash++;
+            l = slash - path;
+            /* XXX we must return NULL here and test in the caller */
+            if (l > MAXPATHLEN)
+                l = MAXPATHLEN;
+            memcpy( pathbuf, path, l);
         } else {
-            pathbuf[ 0 ] = '\0';
-            slash = buf;
+            l = 0;
+            slash = path;
         }
+        l += strlcpy( pathbuf +l, ".AppleDouble/", sizeof(pathbuf) -l);
+        strlcpy( pathbuf + l, slash, sizeof(pathbuf) -l);
     }
-    strlcat( pathbuf, ".AppleDouble/", MAXPATHLEN +1);
-    strlcat( pathbuf, slash, MAXPATHLEN +1);
 
-    if ((adflags == ADFLAGS_RF)) {
-        strlcat( pathbuf, "/AFP_Resource", MAXPATHLEN +1);
-    }
-    else {
-        strlcat( pathbuf, "/AFP_AfpInfo", MAXPATHLEN +1);
-    }
     return( pathbuf );
 }
 
-/* -------------------- */
-static int ad_mkrf_sfm(char *path)
-{
-    char *slash;
-    /*
-     * Probably .AppleDouble doesn't exist, try to mkdir it.
-     */
-    if (NULL == ( slash = strrchr( path, '/' )) ) {
-        return -1;
-    }
-    *slash = 0;
-    errno = 0;
-    if ( ad_mkdir( path, 0777 ) < 0 ) {
-        if ( errno == ENOENT ) {
-            char *slash1;
-
-            if (NULL == ( slash1 = strrchr( path, '/' )) )
-                return -1;
-            errno = 0;
-            *slash1 = 0;
-            if ( ad_mkdir( path, 0777 ) < 0 )
-                return -1;
-            *slash1 = '/';
-            if ( ad_mkdir( path, 0777 ) < 0 )
-                return -1;
-        }
-        else
-            return -1;
-    }
-    *slash = '/';
-    return 0;
-}
-
 /* -------------------------
  * Support inherited protection modes for AppleDouble files.  The supplied
  * mode is ANDed with the parent directory's mask value in lieu of "umask",
  * and that value is returned.
  */
-
-#define DEFMASK 07700   /* be conservative */
-
-char
-*ad_dir(const char *path)
+char *ad_dir(const char *path)
 {
     static char     modebuf[ MAXPATHLEN + 1];
     char        *slash;
@@ -987,9 +892,6 @@ use_cur:
     return modebuf;
 }
 
-/* ---------------- */
-static uid_t default_uid = -1;
-
 int ad_setfuid(const uid_t id)
 {
     default_uid = id;
@@ -1003,211 +905,159 @@ uid_t ad_getfuid(void)
 }
 
 /* ----------------
-   return inode of path parent directory
+   stat path parent directory
 */
 int ad_stat(const char *path, struct stat *stbuf)
 {
-    char                *p;
+    char *p;
 
     p = ad_dir(path);
-    if (!p) {
-        return -1;
-    }
-//FIXME!
-    return lstat( p, stbuf );
-}
-
-/* ----------------
-   if we are root change path user/ group
-   It can be a native function for BSD cf. FAQ.Q10
-   path:  pathname to chown
-   stbuf: parent directory inode
-
-   use fstat and fchown or lchown with linux?
-*/
-#define EMULATE_SUIDDIR
-
-static int ad_chown(const char *path, struct stat *stbuf)
-{
-    int ret = 0;
-#ifdef EMULATE_SUIDDIR
-    uid_t id;
-
-    if (default_uid != (uid_t)-1) {
-        /* we are root (admin) */
-        id = (default_uid)?default_uid:stbuf->st_uid;
-        ret = lchown( path, id, stbuf->st_gid );
-    }
-#endif
-    return ret;
-}
-
-/* ----------------
-   return access right and inode of path parent directory
-*/
-static int ad_mode_st(const char *path, int *mode, struct stat *stbuf)
-{
-    if (*mode == 0) {
+    if (!p)
         return -1;
-    }
-    if (ad_stat(path, stbuf) != 0) {
-        *mode &= DEFMASK;
-        return -1;
-    }
-    *mode &= stbuf->st_mode;
-    return 0;
-}
-
-/* ----------------
-   return access right of path parent directory
-*/
-int
-ad_mode( const char *path, int mode)
-{
-    struct stat     stbuf;
-    ad_mode_st(path, &mode, &stbuf);
-    return mode;
-}
-
-/*
- * Use mkdir() with mode bits taken from ad_mode().
- */
-int
-ad_mkdir( const char *path, int mode)
-{
-    int ret;
-    int st_invalid;
-    struct stat stbuf;
-
-    LOG(log_debug, logtype_default, "ad_mkdir(\"%s\", %04o) {cwd: \"%s\"}",
-        path, mode, getcwdpath());
-
-    st_invalid = ad_mode_st(path, &mode, &stbuf);
-    ret = mkdir( path, mode );
-    if (ret || st_invalid)
-        return ret;
-    ad_chown(path, &stbuf);
-
-    return ret;
-}
-
-/* ----------------- */
-static int ad_error(struct adouble *ad, int adflags)
-{
-    int err = errno;
-    if ((adflags & ADFLAGS_NOHF)) {
-        /* FIXME double check : set header offset ?*/
-        return 0;
-    }
-    if ((adflags & ADFLAGS_DF)) {
-        ad_close( ad, ADFLAGS_DF );
-        err = errno;
-    }
-    return -1 ;
-}
-
-static int new_rfork(const char *path, struct adouble *ad, int adflags);
-
-#ifdef  HAVE_PREAD
-#define AD_SET(a)
-#else
-#define AD_SET(a) a = 0
-#endif
-
-/* --------------------------- */
-static int ad_check_size(struct adouble *ad _U_, struct stat *st)
-{
-    if (st->st_size > 0 && st->st_size < AD_DATASZ1)
-        return 1;
-    return 0;
-}
-
-/* --------------------------- */
-static int ad_check_size_sfm(struct adouble *ad _U_, struct stat *st)
-{
-    if (st->st_size > 0 && st->st_size < AD_SFM_LEN)
-        return 1;
-    return 0;
-}
-
-/* --------------------------- */
-static int ad_header_upgrade(struct adouble *ad, char *name)
-{
-#if AD_VERSION == AD_VERSION2
-    int ret;
-    if ( (ret = ad_convert(ad, name)) < 0 || (ret = ad_update(ad, name) < 0)) {
-        return ret;
-    }
-#endif
-    return 0;
+    return lstat( p, stbuf );
 }
 
-/* --------------------------- */
-static int ad_header_upgrade_none(struct adouble *ad _U_, char *name _U_)
+/* ----------------
+   return access right of path parent directory
+*/
+int ad_mode( const char *path, int mode)
 {
-    return 0;
+    struct stat     stbuf;
+    ad_mode_st(path, &mode, &stbuf);
+    return mode;
 }
 
-/* --------------------------- */
-static struct adouble_fops ad_osx = {
-    &ad_path_osx,
-    &ad_mkrf_osx,
-    &ad_rebuild_adouble_header,
-    &ad_check_size,
-
-    &ad_header_read,
-    &ad_header_upgrade,
-};
-
-static struct adouble_fops ad_sfm = {
-    &ad_path_sfm,
-    &ad_mkrf_sfm,
-    &ad_rebuild_sfm_header,
-    &ad_check_size_sfm,
-
-    &ad_header_sfm_read,
-    &ad_header_upgrade_none,
-};
+/*
+ * Use mkdir() with mode bits taken from ad_mode().
+ */
+int ad_mkdir( const char *path, int mode)
+{
+    int ret;
+    int st_invalid;
+    struct stat stbuf;
 
-static struct adouble_fops ad_adouble = {
-    &ad_path,
-    &ad_mkrf,
-    &ad_rebuild_adouble_header,
-    &ad_check_size,
+    LOG(log_debug, logtype_default, "ad_mkdir(\"%s\", %04o) {cwd: \"%s\"}",
+        path, mode, getcwdpath());
 
-    &ad_header_read,
-    &ad_header_upgrade,
-};
+    st_invalid = ad_mode_st(path, &mode, &stbuf);
+    ret = mkdir( path, mode );
+    if (ret || st_invalid)
+        return ret;
+    ad_chown(path, &stbuf);
 
+    return ret;
+}
 
 void ad_init(struct adouble *ad, int flags, int options)
 {
     ad->ad_inited = 0;
     ad->ad_flags = flags;
-    if (flags == AD_VERSION2_OSX) {
-        ad->ad_ops = &ad_osx;
+    if (flags == AD_VERSION2) {
+        ad->ad_ops = &ad_adouble;
         ad->ad_md = &ad->ad_resource_fork;
     }
-    else if (flags == AD_VERSION1_SFM) {
-        ad->ad_ops = &ad_sfm;
+    else if (flags == AD_VERSION_EA) {
+        ad->ad_ops = &ad_adouble_ea;
         ad->ad_md = &ad->ad_metadata_fork;
+    } else {
+        LOG(log_error, logtype_default, "ad_init: unknown AD version");
+        errno = EIO;
+        return;
     }
-    else {
-        ad->ad_ops = &ad_adouble;
-        ad->ad_md = &ad->ad_resource_fork;
-    }
+
     ad->ad_options = options;
 
     ad_data_fileno(ad) = -1;
     ad_reso_fileno(ad) = -1;
     ad_meta_fileno(ad) = -1;
-    /* following can be read even if there's no
-     * meda data.
-     */
+
+    /* following can be read even if there's no meda data. */
     memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
     ad->ad_rlen = 0;
 }
 
+static const char *adflags2logstr(int adflags)
+{
+    int first = 1;
+    static char buf[64];
+
+    buf[0] = 0;
+
+    if (adflags & ADFLAGS_DF) {
+        strlcat(buf, "DF", 64);
+        first = 0;
+    }
+    if (adflags & ADFLAGS_RF) {
+        if (!first)
+            strlcat(buf, "|", 64);
+        strlcat(buf, "RF", 64);
+        first = 0;
+    }
+    if (adflags & ADFLAGS_HF) {
+        if (!first)
+            strlcat(buf, "|", 64);
+        strlcat(buf, "HF", 64);
+        first = 0;
+    }
+    if (adflags & ADFLAGS_NOHF) {
+        if (!first)
+            strlcat(buf, "|", 64);
+        strlcat(buf, "NOHF", 64);
+        first = 0;
+    }
+    if (adflags & ADFLAGS_DIR) {
+        if (!first)
+            strlcat(buf, "|", 64);
+        strlcat(buf, "DIR", 64);
+        first = 0;
+    }
+    if (adflags & ADFLAGS_RDONLY) {
+        if (!first)
+            strlcat(buf, "|", 64);
+        strlcat(buf, "RDONLY", 64);
+        first = 0;
+    }
+    if (adflags & ADFLAGS_OPENFORKS) {
+        if (!first)
+            strlcat(buf, "|", 64);
+        strlcat(buf, "OF", 64);
+        first = 0;
+    }
+    return buf;
+}
+
+static const char *oflags2logstr(int oflags)
+{
+    int first = 1;
+    static char buf[64];
+
+    buf[0] = 0;
+
+    if (oflags & O_RDONLY) {
+        strlcat(buf, "O_RDONLY", 64);
+        first = 0;
+    }
+    if (oflags & O_RDWR) {
+        if (!first)
+            strlcat(buf, "|", 64);
+        strlcat(buf, "O_RDWR", 64);
+        first = 0;
+    }
+    if (oflags & O_CREAT) {
+        if (!first)
+            strlcat(buf, "|", 64);
+        strlcat(buf, "O_CREAT", 64);
+        first = 0;
+    }
+    if (oflags & O_EXCL) {
+        if (!first)
+            strlcat(buf, "|", 64);
+        strlcat(buf, "O_EXCL", 64);
+        first = 0;
+    }
+    return buf;
+}
+
 /*!
  * Open data-, metadata(header)- or ressource fork
  *
@@ -1219,26 +1069,21 @@ void ad_init(struct adouble *ad, int flags, int options)
  *
  * @param path    Path to file or directory
  *
- * @param adflags ADFLAGS_DF: open data file/fork\n
- *                ADFLAGS_HF: open header (metadata) file\n
- *                ADFLAGS_RF: open ressource fork *** FIXME: not used ?! *** \n
- *                ADFLAGS_CREATE: indicate creation\n
- *                ADFLAGS_NOHF: it's not an error if header file couldn't be created\n
- *                ADFLAGS_DIR: if path is a directory you MUST or ADFLAGS_DIR to adflags\n
- *                ADFLAGS_NOADOUBLE: dont create adouble files if not necessary\n
- *                ADFLAGS_RDONLY: open read only\n
- *                ADFLAGS_OPENFORKS: check for open forks from other processes\n
- *                ADFLAGS_MD: alias for ADFLAGS_HF\n
- *                ADFLAGS_V1COMPAT: obsolete
+ * @param adflags ADFLAGS_DF:        open data fork \n
+ *                ADFLAGS_RF:        open ressource fork \n
+ *                ADFLAGS_HF:        open header (metadata) file \n
+ *                ADFLAGS_NOHF:      it's not an error if header file couldn't be created \n
+ *                ADFLAGS_DIR:       if path is a directory you MUST or ADFLAGS_DIR to adflags \n
+ *                ADFLAGS_RDONLY:    open read only \n
+ *                ADFLAGS_OPENFORKS: check for open forks from other processes
  *
  * @param oflags  flags passed through to open syscall: \n
  *                O_RDONLY: *** FIXME *** \n
  *                O_RDWR: *** FIXME *** \n
- *                O_CREAT: create fork\n
+ *                O_CREAT: create fork \n
  *                O_EXCL: fail if exists with O_CREAT
  *
  * @param mode    passed to open with O_CREAT
- *
  * @param ad      pointer to struct adouble
  *
  * @returns 0 on success
@@ -1247,15 +1092,10 @@ void ad_init(struct adouble *ad, int flags, int options)
  *       will fail and return an error. this refcounts things now.\n
  *       metadata(ressource)-fork only gets created with O_CREAT.
  */
-int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble  *ad)
+int ad_open(const char *path, int adflags, int oflags, int mode, struct adouble  *ad)
 {
-    struct stat         st_dir;
-    struct stat         st_meta;
-    struct stat         *pst = NULL;
-    char        *ad_p;
-    int         hoflags, admode;
-    int                 st_invalid = -1;
-    int                 open_df = 0;
+    LOG(log_debug, logtype_default, "ad_open(\"%s\", %s, %s, 0%04o)",
+        abspath(path), adflags2logstr(adflags), oflags2logstr(oflags), mode);
 
     if (ad->ad_inited != AD_INITED) {
         ad->ad_inited = AD_INITED;
@@ -1264,9 +1104,8 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
         ad->ad_adflags = adflags;
         ad->ad_resource_fork.adf_refcount = 0;
         ad->ad_data_fork.adf_refcount = 0;
-        ad->ad_data_fork.adf_syml=0;
-    }
-    else {
+        ad->ad_data_fork.adf_syml = 0;
+    } else {
         ad->ad_open_forks = ((ad->ad_data_fork.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
         /* XXX not true if we have a meta data fork ? */
         if ((ad->ad_resource_fork.adf_refcount > ad->ad_data_fork.adf_refcount))
@@ -1274,253 +1113,23 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
     }
 
     if ((adflags & ADFLAGS_DF)) {
-        if (ad_data_fileno(ad) == -1) {
-            hoflags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
-            admode = mode;
-            if ((oflags & O_CREAT)) {
-                st_invalid = ad_mode_st(path, &admode, &st_dir);
-                if ((ad->ad_options & ADVOL_UNIXPRIV)) {
-                    admode = mode;
-                }
-            }
-                
-            ad->ad_data_fork.adf_fd =open( path, hoflags | O_NOFOLLOW, admode );
-            
-            if (ad->ad_data_fork.adf_fd == -1) {
-                if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
-                    hoflags = oflags;
-                    ad->ad_data_fork.adf_fd = open( path, hoflags | O_NOFOLLOW, admode );
-                }
-                if (ad->ad_data_fork.adf_fd == -1 && errno == OPEN_NOFOLLOW_ERRNO) {
-                    int lsz;
-
-                    ad->ad_data_fork.adf_syml = malloc(MAXPATHLEN+1);
-                    lsz = readlink(path, ad->ad_data_fork.adf_syml, MAXPATHLEN);
-                    if (lsz <= 0) {
-                        free(ad->ad_data_fork.adf_syml);
-                        return -1;
-                    }
-                    ad->ad_data_fork.adf_syml[lsz] = 0;
-                    ad->ad_data_fork.adf_fd = -2; /* -2 means its a symlink */
-                }
-            }
-
-            if ( ad->ad_data_fork.adf_fd == -1 )
-                return -1;
-
-            AD_SET(ad->ad_data_fork.adf_off);
-            ad->ad_data_fork.adf_flags = hoflags;
-            if (!st_invalid) {
-                /* just created, set owner if admin (root) */
-                ad_chown(path, &st_dir);
-            }
-            adf_lock_init(&ad->ad_data_fork);
-        }
-        else {
-            /* the file is already open... but */
-            if ((oflags & ( O_RDWR | O_WRONLY)) &&             /* we want write access */
-                !(ad->ad_data_fork.adf_flags & ( O_RDWR | O_WRONLY))) /* and it was denied the first time */
-            {
-                errno = EACCES;
-                return -1;
-            }
-            /* FIXME
-             * for now ad_open is never called with O_TRUNC or O_EXCL if the file is
-             * already open. Should we check for it? ie
-             * O_EXCL --> error
-             * O_TRUNC --> truncate the fork.
-             * idem for ressource fork.
-             */
-        }
-        open_df = ADFLAGS_DF;
-        ad->ad_data_fork.adf_refcount++;
-    }
-
-    if (!(adflags & ADFLAGS_HF))
-        return 0;
-
-    /* ****************************************** */
-
-    if (ad_meta_fileno(ad) != -1) { /* the file is already open */
-        if ((oflags & ( O_RDWR | O_WRONLY)) &&
-            !(ad->ad_md->adf_flags & ( O_RDWR | O_WRONLY))) {
-            if (open_df) {
-                /* don't call with ADFLAGS_HF because we didn't open ressource fork */
-                ad_close( ad, open_df );
-            }
-            errno = EACCES;
+        if (ad_open_df(path, adflags, oflags, mode, ad) != 0)
             return -1;
-        }
-        ad_refresh(ad);
-        /* it's not new anymore */
-        ad->ad_md->adf_flags &= ~( O_TRUNC | O_CREAT );
-        ad->ad_md->adf_refcount++;
-        goto sfm;
-    }
-
-    memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
-    ad->ad_rlen = 0;
-    ad_p = ad->ad_ops->ad_path( path, adflags );
-
-    hoflags = oflags & ~(O_CREAT | O_EXCL);
-    if (!(adflags & ADFLAGS_RDONLY)) {
-        hoflags = (hoflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
-    }
-    ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 );
-    if (ad->ad_md->adf_fd < 0 ) {
-        if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
-            hoflags = oflags & ~(O_CREAT | O_EXCL);
-            ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 );
-        }
-    }
-
-    if ( ad->ad_md->adf_fd < 0 ) {
-        if (errno == ENOENT && (oflags & O_CREAT) ) {
-            /*
-             * We're expecting to create a new adouble header file,
-             * here.
-             * if ((oflags & O_CREAT) ==> (oflags & O_RDWR)
-             */
-            LOG(log_debug, logtype_default, "ad_open(\"%s\"): {cwd: \"%s\"} creating adouble file",
-                ad_p, getcwdpath());
-            admode = mode;
-            errno = 0;
-            st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
-            if ((ad->ad_options & ADVOL_UNIXPRIV)) {
-                admode = mode;
-            }
-            admode = ad_hf_mode(admode);
-            if ((errno == ENOENT) && (ad->ad_flags != AD_VERSION2_OSX)) {
-                if (ad->ad_ops->ad_mkrf( ad_p) < 0) {
-                    return ad_error(ad, adflags);
-                }
-                admode = mode;
-                st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
-                if ((ad->ad_options & ADVOL_UNIXPRIV)) {
-                    admode = mode;
-                }
-                admode = ad_hf_mode(admode);
-            }
-            /* retry with O_CREAT */
-            ad->ad_md->adf_fd = open( ad_p, oflags,admode );
-            if ( ad->ad_md->adf_fd < 0 ) {
-                return ad_error(ad, adflags);
-            }
-            ad->ad_md->adf_flags = oflags;
-            /* just created, set owner if admin owner (root) */
-            if (!st_invalid) {
-                ad_chown(ad_p, &st_dir);
-            }
-        }
-        else {
-            return ad_error(ad, adflags);
-        }
-    } else {
-        ad->ad_md->adf_flags = hoflags;
-        if (fstat(ad->ad_md->adf_fd, &st_meta) == 0 && st_meta.st_size == 0) {
-            /* for 0 length files, treat them as new. */
-            ad->ad_md->adf_flags |= O_TRUNC;
-        } 
-        else {
-            /* we have valid data in st_meta stat structure, reused it
-               in ad_header_read
-            */
-            pst = &st_meta;
-        }
     }
-    AD_SET(ad->ad_md->adf_off);
-
-    ad->ad_md->adf_refcount = 1;
-    adf_lock_init(ad->ad_md);
-    if ((ad->ad_md->adf_flags & ( O_TRUNC | O_CREAT ))) {
-        /*
-         * This is a new adouble header file. Initialize the structure,
-         * instead of reading it.
-         */
-        if (new_rfork(path, ad, adflags) < 0) {
-            int err = errno;
-            /* the file is already deleted, perm, whatever, so return an error*/
-            ad_close(ad, adflags);
-            errno = err;
-            return -1;
-        }
-        ad_flush(ad);
-    } else {
-        /* Read the adouble header in and parse it.*/
-        if (ad->ad_ops->ad_header_read( ad , pst) < 0
-            || ad->ad_ops->ad_header_upgrade(ad, ad_p) < 0)
-        {
-            int err = errno;
 
-            ad_close( ad, adflags );
-            errno = err;
+    if ((adflags & ADFLAGS_HF)) {
+        if (ad_open_hf(path, adflags, oflags, mode, ad) != 0)
             return -1;
-        }
-    }
-
-    /* ****************************************** */
-    /* open the resource fork if SFM */
-sfm:
-    if (ad->ad_flags != AD_VERSION1_SFM) {
-        return 0;
-    }
-
-    if ((adflags & ADFLAGS_DIR)) {
-        /* no resource fork for directories / volumes XXX it's false! */
-        return 0;
     }
 
-    /* untrue yet but ad_close will decremente it*/
-    ad->ad_resource_fork.adf_refcount++;
-
-    if (ad_reso_fileno(ad) != -1) { /* the file is already open */
-        if ((oflags & ( O_RDWR | O_WRONLY)) &&
-            !(ad->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
-
-            ad_close( ad, open_df | ADFLAGS_HF);
-            errno = EACCES;
+#if 0
+    if ((adflags & ADFLAGS_RF)) {
+        if (ad_open_rf(path, adflags, oflags, mode, ad) != 0)
             return -1;
-        }
-        return 0;
-    }
-
-    ad_p = ad->ad_ops->ad_path( path, ADFLAGS_RF );
-
-    admode = mode;
-    st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
-
-    if ((ad->ad_options & ADVOL_UNIXPRIV)) {
-        admode = mode;
-    }
-
-    hoflags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
-    ad->ad_resource_fork.adf_fd = open( ad_p, hoflags, admode );
-
-    if (ad->ad_resource_fork.adf_fd < 0 ) {
-        if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
-            hoflags = oflags;
-            ad->ad_resource_fork.adf_fd =open( ad_p, hoflags, admode );
-        }
     }
+#endif
 
-    if ( ad->ad_resource_fork.adf_fd < 0) {
-        int err = errno;
-
-        ad_close( ad, adflags );
-        errno = err;
-        return -1;
-    }
-    adf_lock_init(&ad->ad_resource_fork);
-    AD_SET(ad->ad_resource_fork.adf_off);
-    ad->ad_resource_fork.adf_flags = hoflags;
-    if ((oflags & O_CREAT) && !st_invalid) {
-        /* just created, set owner if admin (root) */
-        ad_chown(ad_p, &st_dir);
-    }
-    else if (!fstat(ad->ad_resource_fork.adf_fd, &st_meta)) {
-        ad->ad_rlen = st_meta.st_size;
-    }
-    return 0 ;
+    return 0;
 }
 
 /*!
@@ -1616,81 +1225,10 @@ exit:
 
 }
 
-/* ----------------------------------- */
-static int new_rfork(const char *path, struct adouble *ad, int adflags)
-{
-    const struct entry  *eid;
-    u_int16_t           ashort;
-    struct stat         st;
-
-    ad->ad_magic = AD_MAGIC;
-    ad->ad_version = ad->ad_flags & 0x0f0000;
-    if (!ad->ad_version) {
-        ad->ad_version = AD_VERSION;
-    }
-
-    memset(ad->ad_filler, 0, sizeof( ad->ad_filler ));
-    memset(ad->ad_data, 0, sizeof(ad->ad_data));
-
-#if AD_VERSION == AD_VERSION2
-    if (ad->ad_flags == AD_VERSION2)
-        eid = entry_order2;
-    else if (ad->ad_flags == AD_VERSION2_OSX)
-        eid = entry_order_osx;
-    else  if (ad->ad_flags == AD_VERSION1_SFM) {
-        ad->ad_magic = SFM_MAGIC;
-        eid = entry_order_sfm;
-    }
-    else
-#endif
-        eid = entry_order1;
-
-    while (eid->id) {
-        ad->ad_eid[eid->id].ade_off = eid->offset;
-        ad->ad_eid[eid->id].ade_len = eid->len;
-        eid++;
-    }
-
-    /* put something sane in the directory finderinfo */
-    if ((adflags & ADFLAGS_DIR)) {
-        /* set default view */
-        ashort = htons(FINDERINFO_CLOSEDVIEW);
-        memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRVIEWOFF,
-               &ashort, sizeof(ashort));
-    } else {
-        /* set default creator/type fields */
-        memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,"\0\0\0\0", 4);
-        memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,"\0\0\0\0", 4);
-    }
-
-    /* make things invisible */
-    if ((ad->ad_options & ADVOL_INVDOTS) && !(adflags & ADFLAGS_CREATE) &&
-        (*path == '.') && strcmp(path, ".") && strcmp(path, ".."))
-    {
-        ashort = htons(ATTRBIT_INVISIBLE);
-        ad_setattr(ad, ashort);
-        ashort = htons(FINDERINFO_INVISIBLE);
-        memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
-    }
-
-    if (lstat(path, &st) < 0) {
-        return -1;
-    }
-
-    /* put something sane in the date fields */
-    ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, st.st_mtime);
-    ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, st.st_mtime);
-    ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, st.st_mtime);
-    ad_setdate(ad, AD_DATE_BACKUP, AD_DATE_START);
-    return 0;
-}
-
-/* to do this with mmap, we need the hfs fs to understand how to mmap
-   header files. */
 int ad_refresh(struct adouble *ad)
 {
 
-    if (ad_meta_fileno(ad) < 0)
+    if (ad_meta_fileno(ad) == -1)
         return -1;
 
     return ad->ad_ops->ad_header_read(ad, NULL);
index 30e26a29c3440b7e4997ed64ba8ab546f4661be5..15e1ff3de028070d7d440fcf97ab3040de88747a 100644 (file)
 #if defined(NEED_RQUOTA) || (defined(sun) && defined(__svr4__)) || \
 (defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ < 6)
 
+#ifndef u_int
+#define u_int unsigned
+#endif
+
 #include <rpc/rpc.h>
 #include <rpcsvc/rquota.h>
 
index 9e71fcb4b71a3b7fd53479c4cebc2cef7cb3bb30..ab0c25e53cf7669f90409a20b50ebf308c71b223 100644 (file)
@@ -57,6 +57,31 @@ const char *getcwdpath(void)
         return strerror(errno);
 }
 
+/*!
+ * Make argument path absoulte
+ *
+ * @returns pointer to path or pointer to error messages on error
+ */
+const char *abspath(const char *name)
+{
+    static char buf[MAXPATHLEN + 1];
+    char *p;
+    int n;
+
+    if (name[0] == '/')
+        return name;
+
+    if ((p = getcwd(buf, MAXPATHLEN)) == NULL)
+        return strerror(errno);
+
+    n = strlen(buf);
+    if (buf[n-1] != '/')
+        buf[n++] = '/';
+        
+    strlcpy(buf + n, name, MAXPATHLEN - n);
+    return buf;
+}
+
 /*!
  * Takes a buffer with a path, strips slashs, returns basename
  *
index 62afbc6559b490aa0d6c62a76380bc170aefe0c5..6dec61a0ccf4f817d91d9128be7629ea2469a6bf 100644 (file)
@@ -299,21 +299,14 @@ static int parseline ( char *buf, struct volinfo *vol)
           strcpy(vol->v_dbpath, value);
         break;
       case ADOUBLE_VER:
-        if (strcasecmp(value, "v1") == 0) {
-            vol->v_adouble = AD_VERSION1;
-            vol->ad_path = ad_path;
-        }
-#if AD_VERSION == AD_VERSION2
-        else if (strcasecmp(value, "v2") == 0) {
+        if (strcasecmp(value, "v2") == 0) {
             vol->ad_path = ad_path;
             vol->v_adouble = AD_VERSION2;
-        }
-        else if (strcasecmp(value, "osx") == 0) {
-            vol->v_adouble = AD_VERSION2_OSX;
-            vol->ad_path = ad_path_osx;
-        }
-#endif
-        else  {
+        } else if (strcasecmp(value, "ea") == 0) {
+            vol->ad_path = ad_path_ea;
+            vol->v_adouble = AD_VERSION_EA;
+        } else {
+
            fprintf (stderr, "unknown adouble version: %s, %s", buf, value);
            return -1;
         }
@@ -514,17 +507,11 @@ int savevolinfo(const struct vol *vol, const char *Cnid_srv, const char *Cnid_po
     strlcat(buf, item, sizeof(buf));
 
     switch (vol->v_adouble) {
-        case AD_VERSION1:
-            strlcat(buf, "ADOUBLE_VER:v1\n", sizeof(buf));
-            break;
         case AD_VERSION2:
             strlcat(buf, "ADOUBLE_VER:v2\n", sizeof(buf));
             break;
-        case AD_VERSION2_OSX:
-            strlcat(buf, "ADOUBLE_VER:osx\n", sizeof(buf));
-            break;
-        case AD_VERSION1_SFM:
-            strlcat(buf, "ADOUBLE_VER:sfm\n", sizeof(buf));
+        case AD_VERSION_EA:
+            strlcat(buf, "ADOUBLE_VER:ea\n", sizeof(buf));
             break;
     }
 
index 9b8d14374c8e4fbb6aeaa86716ce7aff2af73c09..aa62aebffbd591e4a057b23bfe707bfab9eebdb4 100644 (file)
@@ -2,7 +2,7 @@
 
 noinst_LTLIBRARIES = libvfs.la
 
-libvfs_la_SOURCES = vfs.c unix.c ea.c sys_ea.c ea_sys.c
+libvfs_la_SOURCES = vfs.c unix.c ea_ad.c ea_sys.c extattr.c
 
 if HAVE_ACLS
 libvfs_la_SOURCES += acl.c
diff --git a/libatalk/vfs/ea.c b/libatalk/vfs/ea.c
deleted file mode 100644 (file)
index fa3a010..0000000
+++ /dev/null
@@ -1,1768 +0,0 @@
-/*
-  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.
-*/
-
-#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>
-
-/*
- * Store Extended Attributes inside .AppleDouble folders as follows:
- *
- * filename "fileWithEAs" with EAs "testEA1" and "testEA2"
- *
- * - create header with with the format struct adouble_ea_ondisk, the file is written to
- *   ".AppleDouble/fileWithEAs::EA"
- * - store EAs in files "fileWithEAs::EA::testEA1" and "fileWithEAs::EA::testEA2"
- */
-
-/* 
- * Build mode for EA header from file mode
- */
-static inline mode_t ea_header_mode(mode_t mode)
-{
-    /* Same as ad_hf_mode(mode) */
-    mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
-    /* Owner must be able to open, read and w-lock it, in order to chmod from eg 0000 -> 0xxxx*/
-    mode |= S_IRUSR | S_IWUSR;
-    return mode;
-}
-
-/* 
- * Build mode for EA file from file mode
- */
-static inline mode_t ea_mode(mode_t mode)
-{
-    /* Same as ad_hf_mode(mode) */
-    mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
-    return mode;
-}
-
-/*
-  Taken form afpd/desktop.c
-*/
-static char *mtoupath(const struct vol *vol, const char *mpath)
-{
-    static char  upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
-    const char   *m;
-    char         *u;
-    size_t       inplen;
-    size_t       outlen;
-    uint16_t     flags = CONV_ESCAPEHEX | CONV_ALLOW_COLON;
-
-    if (!mpath)
-        return NULL;
-
-    if ( *mpath == '\0' ) {
-        return( "." );
-    }
-
-    m = mpath;
-    u = upath;
-
-    inplen = strlen(m);
-    outlen = MAXPATHLEN;
-
-    if ((size_t)-1 == (outlen = convert_charset(CH_UTF8_MAC,
-                                                vol->v_volcharset,
-                                                vol->v_maccharset,
-                                                m, inplen, u, outlen, &flags)) ) {
-        return NULL;
-    }
-
-    return( upath );
-}
-
-
-/*
- * Function: unpack_header
- *
- * Purpose: unpack and verify header file data buffer at ea->ea_data into struct ea
- *
- * Arguments:
- *
- *    ea      (rw) handle to struct ea
- *
- * Returns: 0 on success, -1 on error
- *
- * Effects:
- *
- * Verifies magic and version.
- */
-static int unpack_header(struct ea * restrict ea)
-{
-    int ret = 0;
-    unsigned int count = 0;
-    uint32_t uint32;
-    char *buf;
-
-    /* Check magic and version */
-    buf = ea->ea_data;
-    if (*(uint32_t *)buf != htonl(EA_MAGIC)) {
-        LOG(log_error, logtype_afpd, "unpack_header: wrong magic 0x%08x", *(uint32_t *)buf);
-        ret = -1;
-        goto exit;
-    }
-    buf += 4;
-    if (*(uint16_t *)buf != htons(EA_VERSION)) {
-        LOG(log_error, logtype_afpd, "unpack_header: wrong version 0x%04x", *(uint16_t *)buf);
-        ret = -1;
-        goto exit;
-    }
-    buf += 2;
-
-    /* Get EA count */
-    ea->ea_count = ntohs(*(uint16_t *)buf);
-    LOG(log_debug, logtype_afpd, "unpack_header: number of EAs: %u", ea->ea_count);
-    buf += 2;
-
-    if (ea->ea_count == 0)
-        return 0;
-
-    /* Allocate storage for the ea_entries array */
-    ea->ea_entries = malloc(sizeof(struct ea_entry) * ea->ea_count);
-    if ( ! ea->ea_entries) {
-        LOG(log_error, logtype_afpd, "unpack_header: OOM");
-        ret = -1;
-        goto exit;
-    }
-
-    buf = ea->ea_data + EA_HEADER_SIZE;
-    while (count < ea->ea_count) {
-        memcpy(&uint32, buf, 4); /* EA size */
-        buf += 4;
-        (*(ea->ea_entries))[count].ea_size = ntohl(uint32);
-        (*(ea->ea_entries))[count].ea_name = strdup(buf);
-        if (! (*(ea->ea_entries))[count].ea_name) {
-            LOG(log_error, logtype_afpd, "unpack_header: OOM");
-            ret = -1;
-            goto exit;
-        }
-        (*(ea->ea_entries))[count].ea_namelen = strlen((*(ea->ea_entries))[count].ea_name);
-        buf += (*(ea->ea_entries))[count].ea_namelen + 1;
-
-        LOG(log_maxdebug, logtype_afpd, "unpack_header: entry no:%u,\"%s\", size: %u, namelen: %u", count,
-            (*(ea->ea_entries))[count].ea_name,
-            (*(ea->ea_entries))[count].ea_size,
-            (*(ea->ea_entries))[count].ea_namelen);
-
-        count++;
-    }
-
-exit:
-    return ret;
-}
-
-/*
- * Function: pack_header
- *
- * Purpose: pack everything from struct ea into buffer at ea->ea_data
- *
- * Arguments:
- *
- *    ea      (rw) handle to struct ea
- *
- * Returns: 0 on success, -1 on error
- *
- * Effects:
- *
- * adjust ea->ea_count in case an ea entry deletetion is detected
- */
-static int pack_header(struct ea * restrict ea)
-{
-    unsigned int count = 0, eacount = 0;
-    uint16_t uint16;
-    uint32_t uint32;
-    size_t bufsize = EA_HEADER_SIZE;
-
-    char *buf = ea->ea_data + EA_HEADER_SIZE;
-
-    LOG(log_debug, logtype_afpd, "pack_header('%s'): ea_count: %u, ea_size: %u",
-        ea->filename, ea->ea_count, ea->ea_size);
-
-    if (ea->ea_count == 0)
-        /* nothing to do, magic, version and count are still valid in buffer */
-        return 0;
-
-    while(count < ea->ea_count) { /* the names */
-        /* Check if its a deleted entry */
-        if ( ! ((*ea->ea_entries)[count].ea_name)) {
-            count++;
-            continue;
-        }
-
-        bufsize += (*(ea->ea_entries))[count].ea_namelen + 1;
-        count++;
-        eacount++;
-    }
-
-    bufsize += (eacount * 4); /* header + ea_size for each EA */
-    if (bufsize > ea->ea_size) {
-        /* we must realloc */
-        if ( ! (buf = realloc(ea->ea_data, bufsize)) ) {
-            LOG(log_error, logtype_afpd, "pack_header: OOM");
-            return -1;
-        }
-        ea->ea_data = buf;
-    }
-    ea->ea_size = bufsize;
-
-    /* copy count */
-    uint16 = htons(eacount);
-    memcpy(ea->ea_data + EA_COUNT_OFF, &uint16, 2);
-
-    count = 0;
-    buf = ea->ea_data + EA_HEADER_SIZE;
-    while (count < ea->ea_count) {
-        /* Check if its a deleted entry */
-        if ( ! ((*ea->ea_entries)[count].ea_name)) {
-            count++;
-            continue;
-        }
-
-        /* First: EA size */
-        uint32 = htonl((*(ea->ea_entries))[count].ea_size);
-        memcpy(buf, &uint32, 4);
-        buf += 4;
-
-        /* Second: EA name as C-string */
-        strcpy(buf, (*(ea->ea_entries))[count].ea_name);
-        buf += (*(ea->ea_entries))[count].ea_namelen + 1;
-
-        LOG(log_maxdebug, logtype_afpd, "pack_header: entry no:%u,\"%s\", size: %u, namelen: %u", count,
-            (*(ea->ea_entries))[count].ea_name,
-            (*(ea->ea_entries))[count].ea_size,
-            (*(ea->ea_entries))[count].ea_namelen);
-
-        count++;
-    }
-
-    ea->ea_count = eacount;
-
-    LOG(log_debug, logtype_afpd, "pack_header('%s'): ea_count: %u, ea_size: %u",
-        ea->filename, ea->ea_count, ea->ea_size);
-    
-    return 0;
-}
-
-/*
- * Function: ea_addentry
- *
- * Purpose: add one EA into ea->ea_entries[]
- *
- * Arguments:
- *
- *    ea            (rw) pointer to struct ea
- *    attruname     (r) name of EA
- *    attrsize      (r) size of ea
- *    bitmap        (r) bitmap from FP func
- *
- * Returns: new number of EA entries, -1 on error
- *
- * Effects:
- *
- * Grow array ea->ea_entries[]. If ea->ea_entries is still NULL, start allocating.
- * Otherwise realloc and put entry at the end. Increments ea->ea_count.
- */
-static int ea_addentry(struct ea * restrict ea,
-                       const char * restrict attruname,
-                       size_t attrsize,
-                       int bitmap)
-{
-    int ea_existed = 0;
-    unsigned int count = 0;
-    void *tmprealloc;
-
-    /* First check if an EA of the requested name already exist */
-    if (ea->ea_count > 0) {
-        while (count < ea->ea_count) {
-            if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) {
-                ea_existed = 1;
-                LOG(log_debug, logtype_afpd, "ea_addentry('%s', bitmap:0x%x): exists", attruname, bitmap);
-                if (bitmap & kXAttrCreate)
-                    /* its like O_CREAT|O_EXCL -> fail */
-                    return -1;
-                (*(ea->ea_entries))[count].ea_size = attrsize;
-                return 0;
-            }
-            count++;
-        }
-    }
-
-    if ((bitmap & kXAttrReplace) && ! ea_existed)
-        /* replace was requested, but EA didn't exist */
-        return -1;
-
-    if (ea->ea_count == 0) {
-        ea->ea_entries = malloc(sizeof(struct ea_entry));
-        if ( ! ea->ea_entries) {
-            LOG(log_error, logtype_afpd, "ea_addentry: OOM");
-            return -1;
-        }
-    } else if (! ea_existed) {
-        tmprealloc = realloc(ea->ea_entries, sizeof(struct ea_entry) * (ea->ea_count + 1));
-        if ( ! tmprealloc) {
-            LOG(log_error, logtype_afpd, "ea_addentry: OOM");
-            return -1;
-        }
-        ea->ea_entries = tmprealloc;
-    }
-
-    /* We've grown the array, now store the entry */
-    (*(ea->ea_entries))[ea->ea_count].ea_size = attrsize;
-    (*(ea->ea_entries))[ea->ea_count].ea_name = strdup(attruname);
-    if ( ! (*(ea->ea_entries))[ea->ea_count].ea_name) {
-        LOG(log_error, logtype_afpd, "ea_addentry: OOM");
-        goto error;
-    }
-    (*(ea->ea_entries))[ea->ea_count].ea_namelen = strlen(attruname);
-
-    ea->ea_count++;
-    return ea->ea_count;
-
-error:
-    if (ea->ea_count == 0 && ea->ea_entries) {
-        /* We just allocated storage but had an error somewhere -> free storage*/
-        free(ea->ea_entries);
-        ea->ea_entries = NULL;
-    }
-    ea->ea_count = 0;
-    return -1;
-}
-
-/*
- * Function: create_ea_header
- *
- * Purpose: create EA header file, only called from ea_open
- *
- * Arguments:
- *
- *    uname       (r)  filename for which we have to create a header
- *    ea          (rw) ea handle with already allocated storage pointed to
- *                     by ea->ea_data
- *
- * Returns: fd of open header file on success, -1 on error, errno semantics:
- *          EEXIST: open with O_CREAT | O_EXCL failed
- *
- * Effects:
- *
- * Creates EA header file and initialize ea->ea_data buffer.
- * Possibe race condition with other afpd processes:
- * we were called because header file didn't exist in eg. ea_open. We then
- * try to create a file with O_CREAT | O_EXCL, but the whole process in not atomic.
- * What do we do then? Someone else is in the process of creating the header too, but
- * it might not have finished it. That means we cant just open, read and use it!
- * We therefor currently just break with an error.
- * On return the header file is still r/w locked.
- */
-static int create_ea_header(const char * restrict uname,
-                            struct ea * restrict ea)
-{
-    int fd = -1, err = 0;
-    char *ptr;
-
-    if ((fd = open(uname, O_RDWR | O_CREAT | O_EXCL, 0666 & ~ea->vol->v_umask)) == -1) {
-        LOG(log_error, logtype_afpd, "ea_create: open race condition with ea header for file: %s", uname);
-        return -1;
-    }
-
-    /* lock it */
-    if ((write_lock(fd, 0, SEEK_SET, 0)) != 0) {
-        LOG(log_error, logtype_afpd, "ea_create: lock race condition with ea header for file: %s", uname);
-        err = -1;
-        goto exit;
-    }
-
-    /* Now init it */
-    ptr = ea->ea_data;
-    *(uint32_t *)ptr = htonl(EA_MAGIC);
-    ptr += EA_MAGIC_LEN;
-    *(uint16_t *)ptr = htons(EA_VERSION);
-    ptr += EA_VERSION_LEN;
-    *(uint16_t *)ptr = 0;       /* count */
-
-    ea->ea_size = EA_HEADER_SIZE;
-    ea->ea_inited = EA_INITED;
-
-exit:
-    if (err != 0) {
-        close(fd);
-        fd = -1;
-    }
-    return fd;
-}
-
-/*
- * Function: write_ea
- *
- * Purpose: write an EA to disk
- *
- * Arguments:
- *
- *    ea         (r) struct ea handle
- *    attruname  (r) EA name
- *    ibuf       (r) buffer with EA content
- *    attrsize   (r) size of EA
- *
- * Returns: 0 on success, -1 on error
- *
- * Effects:
- *
- * Creates/overwrites EA file.
- *
- */
-static int write_ea(const struct ea * restrict ea,
-                    const char * restrict attruname,
-                    const char * restrict ibuf,
-                    size_t attrsize)
-{
-    int fd = -1, ret = AFP_OK;
-    struct stat st;
-    char *eaname;
-
-    if ((eaname = ea_path(ea, attruname, 1)) == NULL) {
-        LOG(log_error, logtype_afpd, "write_ea('%s'): ea_path error", attruname);
-        return AFPERR_MISC;
-    }
-
-    LOG(log_maxdebug, logtype_afpd, "write_ea('%s')", eaname);
-
-    /* Check if it exists, remove if yes*/
-    if ((stat(eaname, &st)) == 0) {
-        if ((unlink(eaname)) != 0) {
-            if (errno == EACCES)
-                return AFPERR_ACCESS;
-            else
-                return AFPERR_MISC;
-        }
-    }
-
-    if ((fd = open(eaname, O_RDWR | O_CREAT | O_EXCL, 0666 & ~ea->vol->v_umask)) == -1) {
-        LOG(log_error, logtype_afpd, "write_ea: open race condition: %s", eaname);
-        return -1;
-    }
-
-    /* lock it */
-    if ((write_lock(fd, 0, SEEK_SET, 0)) != 0) {
-        LOG(log_error, logtype_afpd, "write_ea: open race condition: %s", eaname);
-        ret = -1;
-        goto exit;
-    }
-
-    if (write(fd, ibuf, attrsize) != (ssize_t)attrsize) {
-        LOG(log_error, logtype_afpd, "write_ea('%s'): write: %s", eaname, strerror(errno));
-        ret = -1;
-        goto exit;
-    }
-
-exit:
-    if (fd != -1)
-        close(fd); /* and unlock */
-    return ret;
-}
-
-/*
- * Function: ea_delentry
- *
- * Purpose: delete one EA from ea->ea_entries[]
- *
- * Arguments:
- *
- *    ea            (rw) pointer to struct ea
- *    attruname     (r) EA name
- *
- * Returns: new number of EA entries, -1 on error
- *
- * Effects:
- *
- * Remove entry from  ea->ea_entries[]. Decrement ea->ea_count.
- * Marks it as unused just by freeing name and setting it to NULL.
- * ea_close and pack_buffer must honor this.
- */
-static int ea_delentry(struct ea * restrict ea, const char * restrict attruname)
-{
-    int ret = 0;
-    unsigned int count = 0;
-
-    if (ea->ea_count == 0) {
-        LOG(log_error, logtype_afpd, "ea_delentry('%s'): illegal ea_count of 0 on deletion");
-        return -1;
-    }
-
-    while (count < ea->ea_count) {
-        /* search matching EA */
-        if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) {
-            free((*ea->ea_entries)[count].ea_name);
-            (*ea->ea_entries)[count].ea_name = NULL;
-
-            LOG(log_debug, logtype_afpd, "ea_delentry('%s'): deleted no %u/%u",
-                attruname, count + 1, ea->ea_count);
-
-            break;
-        }
-        count++;
-    }
-
-    return ret;
-}
-
-/*
- * Function: delete_ea_file
- *
- * Purpose: delete EA file from disk
- *
- * Arguments:
- *
- *    ea         (r) struct ea handle
- *    attruname  (r) EA name
- *
- * Returns: 0 on success, -1 on error
- */
-static int delete_ea_file(const struct ea * restrict ea, const char *eaname)
-{
-    int ret = 0;
-    char *eafile;
-    struct stat st;
-
-    if ((eafile = ea_path(ea, eaname, 1)) == NULL) {
-        LOG(log_error, logtype_afpd, "delete_ea_file('%s'): ea_path error", eaname);
-        return -1;
-    }
-
-    /* Check if it exists, remove if yes*/
-    if ((stat(eafile, &st)) == 0) {
-        if ((unlink(eafile)) != 0) {
-            LOG(log_error, logtype_afpd, "delete_ea_file('%s'): unlink: %s",
-                eafile, strerror(errno));
-            ret = -1;
-        } else
-            LOG(log_debug, logtype_afpd, "delete_ea_file('%s'): success", eafile);
-    }
-
-    return ret;
-}
-
-/*************************************************************************************
- * ea_path, ea_open and ea_close are only global so that dbd can call them
- *************************************************************************************/
-
-/*
- * Function: ea_path
- *
- * Purpose: return name of ea header filename
- *
- * Arguments:
- *
- *    ea           (r) ea handle
- *    eaname       (r) name of EA or NULL
- *    macname      (r) if != 0 call mtoupath on eaname
- *
- * Returns: pointer to name in static buffer, NULL on error
- *
- * Effects:
- *
- * Calls ad_open, copies buffer, appends "::EA" and if supplied append eanme
- * Files: "file" -> "file/.AppleDouble/file::EA"
- * Dirs: "dir" -> "dir/.AppleDouble/.Parent::EA"
- * "file" with EA "myEA" -> "file/.AppleDouble/file::EA:myEA"
- */
-char *ea_path(const struct ea * restrict ea, const char * restrict eaname, int macname)
-{
-    char *adname;
-    static char pathbuf[MAXPATHLEN + 1];
-
-    /* get name of a adouble file from uname */
-    adname = ea->vol->ad_path(ea->filename, (ea->ea_flags & EA_DIR) ? ADFLAGS_DIR : 0);
-    /* copy it so we can work with it */
-    strlcpy(pathbuf, adname, MAXPATHLEN + 1);
-    /* append "::EA" */
-    strlcat(pathbuf, "::EA", MAXPATHLEN + 1);
-
-    if (eaname) {
-        strlcat(pathbuf, "::", MAXPATHLEN + 1);
-        if (macname)
-            if ((eaname = mtoupath(ea->vol, eaname)) == NULL)
-                return NULL;
-        strlcat(pathbuf, eaname, MAXPATHLEN + 1);
-    }
-
-    return pathbuf;
-}
-
-/*
- * Function: ea_open
- *
- * Purpose: open EA header file, create if it doesnt exits and called with O_CREATE
- *
- * Arguments:
- *
- *    vol         (r) current volume
- *    uname       (r) filename for which we have to open a header
- *    flags       (r) EA_CREATE: create if it doesn't exist (without it won't be created)
- *                    EA_RDONLY: open read only
- *                    EA_RDWR: open read/write
- *                    Eiterh EA_RDONLY or EA_RDWR MUST be requested
- *    ea          (w) pointer to a struct ea that we fill
- *
- * Returns: 0 on success
- *         -1 on misc error with errno = EFAULT
- *         -2 if no EA header exists with errno = ENOENT
- *
- * Effects:
- *
- * opens header file and stores fd in ea->ea_fd. Size of file is put into ea->ea_size.
- * number of EAs is stored in ea->ea_count. flags are remembered in ea->ea_flags.
- * file is either read or write locked depending on the open flags.
- * When you're done with struct ea you must call ea_close on it.
- */
-int ea_open(const struct vol * restrict vol,
-            const char * restrict uname,
-            eaflags_t eaflags,
-            struct ea * restrict ea)
-{
-    int ret = 0;
-    char *eaname;
-    struct stat st;
-
-    /* Enforce usage rules! */
-    if ( ! (eaflags & (EA_RDONLY | EA_RDWR))) {
-        LOG(log_error, logtype_afpd, "ea_open: called without EA_RDONLY | EA_RDWR", uname);
-        return -1;
-    }
-
-    /* Set it all to 0 */
-    memset(ea, 0, sizeof(struct ea));
-
-    ea->vol = vol;              /* ea_close needs it */
-    ea->ea_flags = eaflags;
-    ea->dirfd = -1;             /* no *at (cf openat) semantics by default */
-
-    /* Dont care for errors, eg when removing the file is already gone */
-    if (!stat(uname, &st) && S_ISDIR(st.st_mode))
-        ea->ea_flags |=  EA_DIR;
-
-    if ( ! (ea->filename = strdup(uname))) {
-        LOG(log_error, logtype_afpd, "ea_open: OOM");
-        return -1;
-    }
-
-    eaname = ea_path(ea, NULL, 0);
-    LOG(log_maxdebug, logtype_afpd, "ea_open: ea_path: %s", eaname);
-
-    /* Check if it exists, if not create it if EA_CREATE is in eaflags */
-    if ((stat(eaname, &st)) != 0) {
-        if (errno == ENOENT) {
-
-            /* It doesnt exist */
-
-            if ( ! (eaflags & EA_CREATE)) {
-                /* creation was not requested, so return with error */
-                ret = -2;
-                goto exit;
-            }
-
-            /* Now create a header file */
-
-            /* malloc buffer for minimal on disk data */
-            ea->ea_data = malloc(EA_HEADER_SIZE);
-            if (! ea->ea_data) {
-                LOG(log_error, logtype_afpd, "ea_open: OOM");
-                ret = -1;
-                goto exit;
-            }
-
-            /* create it */
-            ea->ea_fd = create_ea_header(eaname, ea);
-            if (ea->ea_fd == -1) {
-                ret = -1;
-                goto exit;
-            }
-
-            return 0;
-
-        } else {/* errno != ENOENT */
-            ret = -1;
-            goto exit;
-        }
-    }
-
-    /* header file exists, so read and parse it */
-
-    /* malloc buffer where we read disk file into */
-    if (st.st_size < EA_HEADER_SIZE) {
-        LOG(log_error, logtype_afpd, "ea_open('%s'): bogus EA header file", eaname);
-        ret = -1;
-        goto exit;
-    }
-    ea->ea_size = st.st_size;
-    ea->ea_data = malloc(st.st_size);
-    if (! ea->ea_data) {
-        LOG(log_error, logtype_afpd, "ea_open: OOM");
-        ret = -1;
-        goto exit;
-    }
-
-    /* Now lock, open and read header file from disk */
-    if ((ea->ea_fd = open(eaname, (ea->ea_flags & EA_RDWR) ? O_RDWR : O_RDONLY)) == -1) {
-        LOG(log_error, logtype_afpd, "ea_open('%s'): error: %s", eaname, strerror(errno));
-        ret = -1;
-        goto exit;
-    }
-
-    /* lock it */
-    if (ea->ea_flags & EA_RDONLY) {
-        /* read lock */
-        if ((read_lock(ea->ea_fd, 0, SEEK_SET, 0)) != 0) {
-            LOG(log_error, logtype_afpd, "ea_open: lock error on  header: %s", eaname);
-            ret = -1;
-            goto exit;
-        }
-    } else {  /* EA_RDWR */
-        /* write lock */
-        if ((write_lock(ea->ea_fd, 0, SEEK_SET, 0)) != 0) {
-            LOG(log_error, logtype_afpd, "ea_open: lock error on  header: %s", eaname);
-            ret = -1;
-            goto exit;
-        }
-    }
-
-    /* read it */
-    if (read(ea->ea_fd, ea->ea_data, ea->ea_size) != (ssize_t)ea->ea_size) {
-        LOG(log_error, logtype_afpd, "ea_open: short read on header: %s", eaname);
-        ret = -1;
-        goto exit;
-    }
-
-    if ((unpack_header(ea)) != 0) {
-        LOG(log_error, logtype_afpd, "ea_open: error unpacking header for: %s", eaname);
-        ret = -1;
-        goto exit;
-    }
-
-exit:
-    switch (ret) {
-    case 0:
-        ea->ea_inited = EA_INITED;
-        break;
-    case -1:
-        errno = EFAULT; /* force some errno distinguishable from ENOENT */
-        /* fall through */
-    case -2:
-        if (ea->ea_data) {
-            free(ea->ea_data);
-            ea->ea_data = NULL;
-        }
-        if (ea->ea_fd) {
-            close(ea->ea_fd);
-            ea->ea_fd = -1;
-        }
-        break;
-    }
-
-    return ret;
-}
-
-/*
- * Function: ea_openat
- *
- * Purpose: openat like wrapper for ea_open, takes a additional file descriptor
- *
- * Arguments:
- *
- *    vol         (r) current volume
- *    sfd         (r) openat like file descriptor
- *    uname       (r) filename for which we have to open a header
- *    flags       (r) EA_CREATE: create if it doesn't exist (without it won't be created)
- *                    EA_RDONLY: open read only
- *                    EA_RDWR: open read/write
- *                    Eiterh EA_RDONLY or EA_RDWR MUST be requested
- *    ea          (w) pointer to a struct ea that we fill
- *
- * Returns: 0 on success
- *         -1 on misc error with errno = EFAULT
- *         -2 if no EA header exists with errno = ENOENT
- *
- * Effects:
- *
- * opens header file and stores fd in ea->ea_fd. Size of file is put into ea->ea_size.
- * number of EAs is stored in ea->ea_count. flags are remembered in ea->ea_flags.
- * file is either read or write locked depending on the open flags.
- * When you're done with struct ea you must call ea_close on it.
- */
-int ea_openat(const struct vol * restrict vol,
-              int dirfd,
-              const char * restrict uname,
-              eaflags_t eaflags,
-              struct ea * restrict ea)
-{
-    int ret = 0;
-    int cwdfd = -1;
-
-    if (dirfd != -1) {
-        if (((cwdfd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
-            ret = -1;
-            goto exit;
-        }
-    }
-
-    ret = ea_open(vol, uname, eaflags, ea);
-    ea->dirfd = dirfd;
-
-    if (dirfd != -1) {
-        if (fchdir(cwdfd) != 0) {
-            LOG(log_error, logtype_afpd, "ea_openat: cant chdir back, exiting");
-            exit(EXITERR_SYS);
-        }
-    }
-
-
-exit:
-    if (cwdfd != -1)
-        close(cwdfd);
-
-    return ret;
-
-}
-
-/*
- * Function: ea_close
- *
- * Purpose: flushes and closes an ea handle
- *
- * Arguments:
- *
- *    ea          (rw) pointer to ea handle
- *
- * Returns: 0 on success, -1 on error
- *
- * Effects:
- *
- * Flushes and then closes and frees all resouces held by ea handle.
- * Pack data in ea into ea_data, then write ea_data to disk
- */
-int ea_close(struct ea * restrict ea)
-{
-    int ret = 0; 
-    unsigned int count = 0;
-    char *eaname;
-    struct stat st;
-
-    LOG(log_debug, logtype_afpd, "ea_close('%s')", ea->filename);
-
-    if (ea->ea_inited != EA_INITED) {
-        LOG(log_warning, logtype_afpd, "ea_close('%s'): non initialized ea", ea->filename);
-        return 0;
-    }
-
-    /* pack header and write it to disk if it was opened EA_RDWR*/
-    if (ea->ea_flags & EA_RDWR) {
-        if ((pack_header(ea)) != 0) {
-            LOG(log_error, logtype_afpd, "ea_close: pack header");
-            ret = -1;
-        } else {
-            if (ea->ea_count == 0) {
-                /* Check if EA header exists and remove it */
-                eaname = ea_path(ea, NULL, 0);
-                if ((lstatat(ea->dirfd, eaname, &st)) == 0) {
-                    if ((netatalk_unlinkat(ea->dirfd, eaname)) != 0) {
-                        LOG(log_error, logtype_afpd, "ea_close('%s'): unlink: %s",
-                            eaname, strerror(errno));
-                        ret = -1;
-                    }
-                    else
-                        LOG(log_debug, logtype_afpd, "ea_close(unlink '%s'): success", eaname);
-                } else {
-                    /* stat error */
-                    if (errno != ENOENT) {
-                        LOG(log_error, logtype_afpd, "ea_close('%s'): stat: %s",
-                            eaname, strerror(errno));
-                        ret = -1;
-                    }
-                }
-            } else { /* ea->ea_count > 0 */
-                if ((lseek(ea->ea_fd, 0, SEEK_SET)) == -1) {
-                    LOG(log_error, logtype_afpd, "ea_close: lseek: %s", strerror(errno));
-                    ret = -1;
-                    goto exit;
-                }
-
-                if ((ftruncate(ea->ea_fd, 0)) == -1) {
-                    LOG(log_error, logtype_afpd, "ea_close: ftruncate: %s", strerror(errno));
-                    ret = -1;
-                    goto exit;
-                }
-
-                if (write(ea->ea_fd, ea->ea_data, ea->ea_size) != (ssize_t)ea->ea_size) {
-                    LOG(log_error, logtype_afpd, "ea_close: write: %s", strerror(errno));
-                    ret = -1;
-                }
-            }
-        }
-    }
-
-exit:
-    /* free names */
-    while(count < ea->ea_count) {
-        if ( (*ea->ea_entries)[count].ea_name ) {
-            free((*ea->ea_entries)[count].ea_name);
-            (*ea->ea_entries)[count].ea_name = NULL;
-        }
-        count++;
-    }
-    ea->ea_count = 0;
-
-    if (ea->filename) {
-        free(ea->filename);
-        ea->filename = NULL;
-    }
-
-    if (ea->ea_entries) {
-        free(ea->ea_entries);
-        ea->ea_entries = NULL;
-    }
-
-    if (ea->ea_data) {
-        free(ea->ea_data);
-        ea->ea_data = NULL;
-    }
-    if (ea->ea_fd != -1) {
-        close(ea->ea_fd);       /* also releases the fcntl lock */
-        ea->ea_fd = -1;
-    }
-
-    return 0;
-}
-
-
-
-/************************************************************************************
- * VFS funcs called from afp_ea* funcs
- ************************************************************************************/
-
-/*
- * Function: get_easize
- *
- * Purpose: get size of an 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 get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
-{
-    int ret = AFPERR_MISC;
-    unsigned int count = 0;
-    uint32_t uint32;
-    struct ea ea;
-
-    LOG(log_debug, logtype_afpd, "get_easize: file: %s", uname);
-
-    if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) {
-        if (errno != ENOENT)
-            LOG(log_error, logtype_afpd, "get_easize: error calling ea_open for file: %s", uname);
-
-        memset(rbuf, 0, 4);
-        *rbuflen += 4;
-        return ret;
-    }
-
-    while (count < ea.ea_count) {
-        if (strcmp(attruname, (*ea.ea_entries)[count].ea_name) == 0) {
-            uint32 = htonl((*ea.ea_entries)[count].ea_size);
-            memcpy(rbuf, &uint32, 4);
-            *rbuflen += 4;
-            ret = AFP_OK;
-
-            LOG(log_debug, logtype_afpd, "get_easize(\"%s\"): size: %u",
-                attruname, (*ea.ea_entries)[count].ea_size);
-            break;
-        }
-        count++;
-    }
-
-    if ((ea_close(&ea)) != 0) {
-        LOG(log_error, logtype_afpd, "get_easize: error closing ea handle for file: %s", uname);
-        return AFPERR_MISC;
-    }
-
-    return ret;
-}
-
-/*
- * Function: get_eacontent
- *
- * Purpose: copy 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 get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
-{
-    int ret = AFPERR_MISC, fd = -1;
-    unsigned int count = 0;
-    uint32_t uint32;
-    size_t toread;
-    struct ea ea;
-    char *eafile;
-
-    LOG(log_debug, logtype_afpd, "get_eacontent('%s/%s')", uname, attruname);
-
-    if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) {
-        if (errno != ENOENT)
-            LOG(log_error, logtype_afpd, "get_eacontent('%s'): ea_open error", uname);
-        memset(rbuf, 0, 4);
-        *rbuflen += 4;
-        return ret;
-    }
-
-    while (count < ea.ea_count) {
-        if (strcmp(attruname, (*ea.ea_entries)[count].ea_name) == 0) {
-            if ( (eafile = ea_path(&ea, attruname, 1)) == NULL) {
-                ret = AFPERR_MISC;
-                break;
-            }
-
-            if ((fd = open(eafile, O_RDONLY)) == -1) {
-                LOG(log_error, logtype_afpd, "get_eacontent('%s'): open error: %s", uname, strerror(errno));
-                ret = AFPERR_MISC;
-                break;
-            }
-
-            /* Check how much the client wants, give him what we think is right */
-            maxreply -= MAX_REPLY_EXTRA_BYTES;
-            if (maxreply > MAX_EA_SIZE)
-                maxreply = MAX_EA_SIZE;
-            toread = (maxreply < (*ea.ea_entries)[count].ea_size) ? maxreply : (*ea.ea_entries)[count].ea_size;
-            LOG(log_debug, logtype_afpd, "get_eacontent('%s'): sending %u bytes", attruname, toread);
-
-            /* Put length of EA data in reply buffer */
-            uint32 = htonl(toread);
-            memcpy(rbuf, &uint32, 4);
-            rbuf += 4;
-            *rbuflen += 4;
-
-            if (read(fd, rbuf, toread) != (ssize_t)toread) {
-                LOG(log_error, logtype_afpd, "get_eacontent('%s/%s'): short read", uname, attruname);
-                close(fd);
-                ret = AFPERR_MISC;
-                break;
-            }
-            *rbuflen += toread;
-            close(fd);
-
-            ret = AFP_OK;
-            break;
-        }
-        count++;
-    }
-
-    if ((ea_close(&ea)) != 0) {
-        LOG(log_error, logtype_afpd, "get_eacontent('%s'): error closing ea handle", uname);
-        return AFPERR_MISC;
-    }
-
-    return ret;
-
-}
-
-/*
- * Function: list_eas
- *
- * Purpose: copy names of EAs 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 *buflen accordingly.
- */
-int list_eas(VFS_FUNC_ARGS_EA_LIST)
-{
-    unsigned int count = 0;
-    int attrbuflen = *buflen, ret = AFP_OK, len;
-    char *buf = attrnamebuf;
-    struct ea ea;
-
-    LOG(log_debug, logtype_afpd, "list_eas: file: %s", uname);
-
-    if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) {
-        if (errno != ENOENT) {
-            LOG(log_error, logtype_afpd, "list_eas: error calling ea_open for file: %s", uname);
-            return AFPERR_MISC;
-        }
-        else
-            return AFP_OK;
-    }
-
-    while (count < ea.ea_count) {
-        /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
-        if ( ( len = convert_string(vol->v_volcharset,
-                                    CH_UTF8_MAC, 
-                                    (*ea.ea_entries)[count].ea_name,
-                                    (*ea.ea_entries)[count].ea_namelen,
-                                    buf + attrbuflen,
-                                    255))
-             <= 0 ) {
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-        if (len == 255)
-            /* convert_string didn't 0-terminate */
-            attrnamebuf[attrbuflen + 255] = 0;
-
-        LOG(log_debug7, logtype_afpd, "list_eas(%s): EA: %s",
-            uname, (*ea.ea_entries)[count].ea_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, "list_eas(%s): running out of buffer for EA names", uname);
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-        count++;
-    }
-
-exit:
-    *buflen = attrbuflen;
-
-    if ((ea_close(&ea)) != 0) {
-        LOG(log_error, logtype_afpd, "list_eas: error closing ea handle for file: %s", uname);
-        return AFPERR_MISC;
-    }
-
-    return ret;
-}
-
-/*
- * Function: 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 set_ea(VFS_FUNC_ARGS_EA_SET)
-{
-    int ret = AFP_OK;
-    struct ea ea;
-
-    LOG(log_debug, logtype_afpd, "set_ea: file: %s", uname);
-
-    if ((ea_open(vol, uname, EA_CREATE | EA_RDWR, &ea)) != 0) {
-        LOG(log_error, logtype_afpd, "set_ea('%s'): ea_open error", uname);
-        return AFPERR_MISC;
-    }
-
-    if ((ea_addentry(&ea, attruname, attrsize, oflag)) == -1) {
-        LOG(log_error, logtype_afpd, "set_ea('%s'): ea_addentry error", uname);
-        ret = AFPERR_MISC;
-        goto exit;
-    }
-
-    if ((write_ea(&ea, attruname, ibuf, attrsize)) != 0) {
-        LOG(log_error, logtype_afpd, "set_ea('%s'): write_ea error", uname);
-        ret = AFPERR_MISC;
-        goto exit;
-    }
-
-exit:
-    if ((ea_close(&ea)) != 0) {
-        LOG(log_error, logtype_afpd, "set_ea('%s'): ea_close error", uname);
-        ret = AFPERR_MISC;
-        goto exit;
-    }
-
-    return ret;
-}
-
-/*
- * Function: remove_ea
- *
- * Purpose: remove a EA from a file
- *
- * 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 remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
-{
-    int ret = AFP_OK;
-    struct ea ea;
-
-    LOG(log_debug, logtype_afpd, "remove_ea('%s/%s')", uname, attruname);
-
-    if ((ea_open(vol, uname, EA_RDWR, &ea)) != 0) {
-        LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_open error", uname);
-        return AFPERR_MISC;
-    }
-
-    if ((ea_delentry(&ea, attruname)) == -1) {
-        LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_delentry error", uname);
-        ret = AFPERR_MISC;
-        goto exit;
-    }
-
-    if ((delete_ea_file(&ea, attruname)) != 0) {
-        LOG(log_error, logtype_afpd, "remove_ea('%s'): delete_ea error", uname);
-        ret = AFPERR_MISC;
-        goto exit;
-    }
-
-exit:
-    if ((ea_close(&ea)) != 0) {
-        LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_close error", uname);
-        ret = AFPERR_MISC;
-        goto exit;
-    }
-
-    return ret;
-}
-
-/******************************************************************************************
- * EA VFS funcs that deal with file/dir cp/mv/rm
- ******************************************************************************************/
-
-int ea_deletefile(VFS_FUNC_ARGS_DELETEFILE)
-{
-    unsigned int count = 0;
-    int ret = AFP_OK;
-    int cwd = -1;
-    struct ea ea;
-
-    LOG(log_debug, logtype_afpd, "ea_deletefile('%s')", file);
-
-    /* Open EA stuff */
-    if ((ea_openat(vol, dirfd, file, EA_RDWR, &ea)) != 0) {
-        if (errno == ENOENT)
-            /* no EA files, nothing to do */
-            return AFP_OK;
-        else {
-            LOG(log_error, logtype_afpd, "ea_deletefile('%s'): error calling ea_open", file);
-            return AFPERR_MISC;
-        }
-    }
-
-    if (dirfd != -1) {
-        if (((cwd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-    }
-
-    while (count < ea.ea_count) {
-        if ((delete_ea_file(&ea, (*ea.ea_entries)[count].ea_name)) != 0) {
-            ret = AFPERR_MISC;
-            continue;
-        }
-        free((*ea.ea_entries)[count].ea_name);
-        (*ea.ea_entries)[count].ea_name = NULL;
-        count++;
-    }
-
-    /* ea_close removes the EA header file for us because all names are NULL */
-    if ((ea_close(&ea)) != 0) {
-        LOG(log_error, logtype_afpd, "ea_deletefile('%s'): error closing ea handle", file);
-        ret = AFPERR_MISC;
-    }
-
-    if (dirfd != -1 && fchdir(cwd) != 0) {
-        LOG(log_error, logtype_afpd, "ea_deletefile: cant chdir back. exit!");
-        exit(EXITERR_SYS);
-    }
-
-exit:
-    if (cwd != -1)
-        close(cwd);
-
-    return ret;
-}
-
-int ea_renamefile(VFS_FUNC_ARGS_RENAMEFILE)
-{
-    unsigned int count = 0;
-    int    ret = AFP_OK;
-    size_t easize;
-    char   srceapath[ MAXPATHLEN + 1];
-    char   *eapath;
-    char   *eaname;
-    struct ea srcea;
-    struct ea dstea;
-    struct adouble ad;
-
-    LOG(log_debug, logtype_afpd, "ea_renamefile('%s'/'%s')", src, dst);
-            
-
-    /* Open EA stuff */
-    if ((ea_openat(vol, dirfd, src, EA_RDWR, &srcea)) != 0) {
-        if (errno == ENOENT)
-            /* no EA files, nothing to do */
-            return AFP_OK;
-        else {
-            LOG(log_error, logtype_afpd, "ea_renamefile('%s'/'%s'): ea_open error: '%s'", src, dst, src);
-            return AFPERR_MISC;
-        }
-    }
-
-    if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
-        if (errno == ENOENT) {
-            /* Possibly the .AppleDouble folder didn't exist, we create it and try again */
-            ad_init(&ad, vol->v_adouble, vol->v_ad_options); 
-            if ((ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) != 0) {
-                LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): ad_open error: '%s'", src, dst, dst);
-                ret = AFPERR_MISC;
-                goto exit;
-            }
-            ad_close(&ad, ADFLAGS_HF);
-            if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
-                ret = AFPERR_MISC;
-                goto exit;
-            }
-        }
-    }
-
-    /* Loop through all EAs: */
-    while (count < srcea.ea_count) {
-        /* Move EA */
-        eaname = (*srcea.ea_entries)[count].ea_name;
-        easize = (*srcea.ea_entries)[count].ea_size;
-
-        /* Build src and dst paths for rename() */
-        if ((eapath = ea_path(&srcea, eaname, 1)) == NULL) {
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-        strcpy(srceapath, eapath);
-        if ((eapath = ea_path(&dstea, eaname, 1)) == NULL) {
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-
-        LOG(log_maxdebug, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
-            src, dst, srceapath, eapath);
-
-        /* Add EA to dstea */
-        if ((ea_addentry(&dstea, eaname, easize, 0)) == -1) {
-            LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
-                src, dst, srceapath, eapath);
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-
-        /* Remove EA entry from srcea */
-        if ((ea_delentry(&srcea, eaname)) == -1) {
-            LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
-                src, dst, srceapath, eapath);
-            ea_delentry(&dstea, eaname);
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-
-        /* Now rename the EA */
-        if ((unix_rename(dirfd, srceapath, -1, eapath)) < 0) {
-            LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
-                src, dst, srceapath, eapath);
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-
-        count++;
-    }
-
-
-exit:
-    ea_close(&srcea);
-    ea_close(&dstea);
-       return ret;
-}
-
-int ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
-{
-    unsigned int count = 0;
-    int    ret = AFP_OK;
-    size_t easize;
-    char   srceapath[ MAXPATHLEN + 1];
-    char   *eapath;
-    char   *eaname;
-    struct ea srcea;
-    struct ea dstea;
-    struct adouble ad;
-
-    LOG(log_debug, logtype_afpd, "ea_copyfile('%s'/'%s')", src, dst);
-
-    /* Open EA stuff */
-    if ((ea_openat(vol, sfd, src, EA_RDWR, &srcea)) != 0) {
-        if (errno == ENOENT)
-            /* no EA files, nothing to do */
-            return AFP_OK;
-        else {
-            LOG(log_error, logtype_afpd, "ea_copyfile('%s'/'%s'): ea_open error: '%s'", src, dst, src);
-            return AFPERR_MISC;
-        }
-    }
-
-    if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
-        if (errno == ENOENT) {
-            /* Possibly the .AppleDouble folder didn't exist, we create it and try again */
-            ad_init(&ad, vol->v_adouble, vol->v_ad_options); 
-            if ((ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) != 0) {
-                LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): ad_open error: '%s'", src, dst, dst);
-                ret = AFPERR_MISC;
-                goto exit;
-            }
-            ad_close(&ad, ADFLAGS_HF);
-            if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
-                ret = AFPERR_MISC;
-                goto exit;
-            }
-        }
-    }
-
-    /* Loop through all EAs: */
-    while (count < srcea.ea_count) {
-        /* Copy EA */
-        eaname = (*srcea.ea_entries)[count].ea_name;
-        easize = (*srcea.ea_entries)[count].ea_size;
-
-        /* Build src and dst paths for copy_file() */
-        if ((eapath = ea_path(&srcea, eaname, 1)) == NULL) {
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-        strcpy(srceapath, eapath);
-        if ((eapath = ea_path(&dstea, eaname, 1)) == NULL) {
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-
-        LOG(log_maxdebug, logtype_afpd, "ea_copyfile('%s/%s'): copying EA '%s' to '%s'",
-            src, dst, srceapath, eapath);
-
-        /* Add EA to dstea */
-        if ((ea_addentry(&dstea, eaname, easize, 0)) == -1) {
-            LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): ea_addentry('%s') error",
-                src, dst, eaname);
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-
-        /* Now copy the EA */
-        if ((copy_file(sfd, srceapath, eapath, (0666 & ~vol->v_umask))) < 0) {
-            LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): copying EA '%s' to '%s'",
-                src, dst, srceapath, eapath);
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-
-        count++;
-    }
-
-exit:
-    ea_close(&srcea);
-    ea_close(&dstea);
-       return ret;
-}
-
-int ea_chown(VFS_FUNC_ARGS_CHOWN)
-{
-
-    unsigned int count = 0;
-    int ret = AFP_OK;
-    char *eaname;
-    struct ea ea;
-
-    LOG(log_debug, logtype_afpd, "ea_chown('%s')", path);
-    /* Open EA stuff */
-    if ((ea_open(vol, path, EA_RDWR, &ea)) != 0) {
-        if (errno == ENOENT)
-            /* no EA files, nothing to do */
-            return AFP_OK;
-        else {
-            LOG(log_error, logtype_afpd, "ea_chown('%s'): error calling ea_open", path);
-            return AFPERR_MISC;
-        }
-    }
-
-    if ((lchown(ea_path(&ea, NULL, 0), uid, gid)) != 0) {
-        switch (errno) {
-        case EPERM:
-        case EACCES:
-            ret = AFPERR_ACCESS;
-            goto exit;
-        default:
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-    }
-
-    while (count < ea.ea_count) {
-        if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 1)) == NULL) {
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-        if ((lchown(eaname, uid, gid)) != 0) {
-            switch (errno) {
-            case EPERM:
-            case EACCES:
-                ret = AFPERR_ACCESS;
-                goto exit;
-            default:
-                ret = AFPERR_MISC;
-                goto exit;
-            }
-            continue;
-        }
-
-        count++;
-    }
-
-exit:
-    if ((ea_close(&ea)) != 0) {
-        LOG(log_error, logtype_afpd, "ea_chown('%s'): error closing ea handle", path);
-        return AFPERR_MISC;
-    }
-
-    return ret;
-}
-
-int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE)
-{
-
-    unsigned int count = 0;
-    int ret = AFP_OK;
-    const char *eaname;
-    struct ea ea;
-
-    LOG(log_debug, logtype_afpd, "ea_chmod_file('%s')", name);
-    /* Open EA stuff */
-    if ((ea_open(vol, name, EA_RDWR, &ea)) != 0) {
-        if (errno == ENOENT)
-            /* no EA files, nothing to do */
-            return AFP_OK;
-        else
-            return AFPERR_MISC;
-    }
-
-    /* Set mode on EA header file */
-    if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) {
-        LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno));
-        switch (errno) {
-        case EPERM:
-        case EACCES:
-            ret = AFPERR_ACCESS;
-            goto exit;
-        default:
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-    }
-
-    /* Set mode on EA files */
-    while (count < ea.ea_count) {
-        if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 1)) == NULL) {
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-        if ((setfilmode(eaname, ea_mode(mode), NULL, vol->v_umask)) != 0) {
-            LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", eaname, strerror(errno));
-            switch (errno) {
-            case EPERM:
-            case EACCES:
-                ret = AFPERR_ACCESS;
-                goto exit;
-            default:
-                ret = AFPERR_MISC;
-                goto exit;
-            }
-            continue;
-        }
-
-        count++;
-    }
-
-exit:
-    if ((ea_close(&ea)) != 0) {
-        LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): error closing ea handle", name);
-        return AFPERR_MISC;
-    }
-
-    return ret;
-}
-
-int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE)
-{
-
-    int ret = AFP_OK;
-    unsigned int count = 0;
-    uid_t uid;
-    const char *eaname;
-    const char *eaname_safe = NULL;
-    struct ea ea;
-
-    LOG(log_debug, logtype_afpd, "ea_chmod_dir('%s')", name);
-    /* .AppleDouble already might be inaccesible, so we must run as id 0 */
-    uid = geteuid();
-    if (seteuid(0)) {
-        LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): seteuid: %s", name, strerror(errno));
-        return AFPERR_MISC;
-    }
-
-    /* Open EA stuff */
-    if ((ea_open(vol, name, EA_RDWR, &ea)) != 0) {
-        /* ENOENT --> no EA files, nothing to do */
-        if (errno != ENOENT)
-            ret = AFPERR_MISC;
-        if (seteuid(uid) < 0) {
-            LOG(log_error, logtype_afpd, "can't seteuid back: %s", strerror(errno));
-            exit(EXITERR_SYS);
-        }
-        return ret;
-    }
-
-    /* Set mode on EA header */
-    if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) {
-        LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno));
-        switch (errno) {
-        case EPERM:
-        case EACCES:
-            ret = AFPERR_ACCESS;
-            goto exit;
-        default:
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-    }
-
-    /* Set mode on EA files */
-    while (count < ea.ea_count) {
-        eaname = (*ea.ea_entries)[count].ea_name;
-        /*
-         * Be careful with EA names from the EA header!
-         * Eg NFS users might have access to them, can inject paths using ../ or /.....
-         * FIXME:
-         * Until the EA code escapes / in EA name requests from the client, these therefor wont work.
-         */
-        if ((eaname_safe = strrchr(eaname, '/'))) {
-            LOG(log_warning, logtype_afpd, "ea_chmod_dir('%s'): contains a slash", eaname);
-            eaname = eaname_safe;
-        }
-        if ((eaname = ea_path(&ea, eaname, 1)) == NULL) {
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-        if ((setfilmode(eaname, ea_mode(mode), NULL, vol->v_umask)) != 0) {
-            LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", eaname, strerror(errno));
-            switch (errno) {
-            case EPERM:
-            case EACCES:
-                ret = AFPERR_ACCESS;
-                goto exit;
-            default:
-                ret = AFPERR_MISC;
-                goto exit;
-            }
-            continue;
-        }
-
-        count++;
-    }
-
-exit:
-    if (seteuid(uid) < 0) {
-        LOG(log_error, logtype_afpd, "can't seteuid back: %s", strerror(errno));
-        exit(EXITERR_SYS);
-    }
-
-    if ((ea_close(&ea)) != 0) {
-        LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): error closing ea handle", name);
-        return AFPERR_MISC;
-    }
-
-    return ret;
-}
diff --git a/libatalk/vfs/ea_ad.c b/libatalk/vfs/ea_ad.c
new file mode 100644 (file)
index 0000000..fa3a010
--- /dev/null
@@ -0,0 +1,1768 @@
+/*
+  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.
+*/
+
+#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>
+
+/*
+ * Store Extended Attributes inside .AppleDouble folders as follows:
+ *
+ * filename "fileWithEAs" with EAs "testEA1" and "testEA2"
+ *
+ * - create header with with the format struct adouble_ea_ondisk, the file is written to
+ *   ".AppleDouble/fileWithEAs::EA"
+ * - store EAs in files "fileWithEAs::EA::testEA1" and "fileWithEAs::EA::testEA2"
+ */
+
+/* 
+ * Build mode for EA header from file mode
+ */
+static inline mode_t ea_header_mode(mode_t mode)
+{
+    /* Same as ad_hf_mode(mode) */
+    mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+    /* Owner must be able to open, read and w-lock it, in order to chmod from eg 0000 -> 0xxxx*/
+    mode |= S_IRUSR | S_IWUSR;
+    return mode;
+}
+
+/* 
+ * Build mode for EA file from file mode
+ */
+static inline mode_t ea_mode(mode_t mode)
+{
+    /* Same as ad_hf_mode(mode) */
+    mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+    return mode;
+}
+
+/*
+  Taken form afpd/desktop.c
+*/
+static char *mtoupath(const struct vol *vol, const char *mpath)
+{
+    static char  upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
+    const char   *m;
+    char         *u;
+    size_t       inplen;
+    size_t       outlen;
+    uint16_t     flags = CONV_ESCAPEHEX | CONV_ALLOW_COLON;
+
+    if (!mpath)
+        return NULL;
+
+    if ( *mpath == '\0' ) {
+        return( "." );
+    }
+
+    m = mpath;
+    u = upath;
+
+    inplen = strlen(m);
+    outlen = MAXPATHLEN;
+
+    if ((size_t)-1 == (outlen = convert_charset(CH_UTF8_MAC,
+                                                vol->v_volcharset,
+                                                vol->v_maccharset,
+                                                m, inplen, u, outlen, &flags)) ) {
+        return NULL;
+    }
+
+    return( upath );
+}
+
+
+/*
+ * Function: unpack_header
+ *
+ * Purpose: unpack and verify header file data buffer at ea->ea_data into struct ea
+ *
+ * Arguments:
+ *
+ *    ea      (rw) handle to struct ea
+ *
+ * Returns: 0 on success, -1 on error
+ *
+ * Effects:
+ *
+ * Verifies magic and version.
+ */
+static int unpack_header(struct ea * restrict ea)
+{
+    int ret = 0;
+    unsigned int count = 0;
+    uint32_t uint32;
+    char *buf;
+
+    /* Check magic and version */
+    buf = ea->ea_data;
+    if (*(uint32_t *)buf != htonl(EA_MAGIC)) {
+        LOG(log_error, logtype_afpd, "unpack_header: wrong magic 0x%08x", *(uint32_t *)buf);
+        ret = -1;
+        goto exit;
+    }
+    buf += 4;
+    if (*(uint16_t *)buf != htons(EA_VERSION)) {
+        LOG(log_error, logtype_afpd, "unpack_header: wrong version 0x%04x", *(uint16_t *)buf);
+        ret = -1;
+        goto exit;
+    }
+    buf += 2;
+
+    /* Get EA count */
+    ea->ea_count = ntohs(*(uint16_t *)buf);
+    LOG(log_debug, logtype_afpd, "unpack_header: number of EAs: %u", ea->ea_count);
+    buf += 2;
+
+    if (ea->ea_count == 0)
+        return 0;
+
+    /* Allocate storage for the ea_entries array */
+    ea->ea_entries = malloc(sizeof(struct ea_entry) * ea->ea_count);
+    if ( ! ea->ea_entries) {
+        LOG(log_error, logtype_afpd, "unpack_header: OOM");
+        ret = -1;
+        goto exit;
+    }
+
+    buf = ea->ea_data + EA_HEADER_SIZE;
+    while (count < ea->ea_count) {
+        memcpy(&uint32, buf, 4); /* EA size */
+        buf += 4;
+        (*(ea->ea_entries))[count].ea_size = ntohl(uint32);
+        (*(ea->ea_entries))[count].ea_name = strdup(buf);
+        if (! (*(ea->ea_entries))[count].ea_name) {
+            LOG(log_error, logtype_afpd, "unpack_header: OOM");
+            ret = -1;
+            goto exit;
+        }
+        (*(ea->ea_entries))[count].ea_namelen = strlen((*(ea->ea_entries))[count].ea_name);
+        buf += (*(ea->ea_entries))[count].ea_namelen + 1;
+
+        LOG(log_maxdebug, logtype_afpd, "unpack_header: entry no:%u,\"%s\", size: %u, namelen: %u", count,
+            (*(ea->ea_entries))[count].ea_name,
+            (*(ea->ea_entries))[count].ea_size,
+            (*(ea->ea_entries))[count].ea_namelen);
+
+        count++;
+    }
+
+exit:
+    return ret;
+}
+
+/*
+ * Function: pack_header
+ *
+ * Purpose: pack everything from struct ea into buffer at ea->ea_data
+ *
+ * Arguments:
+ *
+ *    ea      (rw) handle to struct ea
+ *
+ * Returns: 0 on success, -1 on error
+ *
+ * Effects:
+ *
+ * adjust ea->ea_count in case an ea entry deletetion is detected
+ */
+static int pack_header(struct ea * restrict ea)
+{
+    unsigned int count = 0, eacount = 0;
+    uint16_t uint16;
+    uint32_t uint32;
+    size_t bufsize = EA_HEADER_SIZE;
+
+    char *buf = ea->ea_data + EA_HEADER_SIZE;
+
+    LOG(log_debug, logtype_afpd, "pack_header('%s'): ea_count: %u, ea_size: %u",
+        ea->filename, ea->ea_count, ea->ea_size);
+
+    if (ea->ea_count == 0)
+        /* nothing to do, magic, version and count are still valid in buffer */
+        return 0;
+
+    while(count < ea->ea_count) { /* the names */
+        /* Check if its a deleted entry */
+        if ( ! ((*ea->ea_entries)[count].ea_name)) {
+            count++;
+            continue;
+        }
+
+        bufsize += (*(ea->ea_entries))[count].ea_namelen + 1;
+        count++;
+        eacount++;
+    }
+
+    bufsize += (eacount * 4); /* header + ea_size for each EA */
+    if (bufsize > ea->ea_size) {
+        /* we must realloc */
+        if ( ! (buf = realloc(ea->ea_data, bufsize)) ) {
+            LOG(log_error, logtype_afpd, "pack_header: OOM");
+            return -1;
+        }
+        ea->ea_data = buf;
+    }
+    ea->ea_size = bufsize;
+
+    /* copy count */
+    uint16 = htons(eacount);
+    memcpy(ea->ea_data + EA_COUNT_OFF, &uint16, 2);
+
+    count = 0;
+    buf = ea->ea_data + EA_HEADER_SIZE;
+    while (count < ea->ea_count) {
+        /* Check if its a deleted entry */
+        if ( ! ((*ea->ea_entries)[count].ea_name)) {
+            count++;
+            continue;
+        }
+
+        /* First: EA size */
+        uint32 = htonl((*(ea->ea_entries))[count].ea_size);
+        memcpy(buf, &uint32, 4);
+        buf += 4;
+
+        /* Second: EA name as C-string */
+        strcpy(buf, (*(ea->ea_entries))[count].ea_name);
+        buf += (*(ea->ea_entries))[count].ea_namelen + 1;
+
+        LOG(log_maxdebug, logtype_afpd, "pack_header: entry no:%u,\"%s\", size: %u, namelen: %u", count,
+            (*(ea->ea_entries))[count].ea_name,
+            (*(ea->ea_entries))[count].ea_size,
+            (*(ea->ea_entries))[count].ea_namelen);
+
+        count++;
+    }
+
+    ea->ea_count = eacount;
+
+    LOG(log_debug, logtype_afpd, "pack_header('%s'): ea_count: %u, ea_size: %u",
+        ea->filename, ea->ea_count, ea->ea_size);
+    
+    return 0;
+}
+
+/*
+ * Function: ea_addentry
+ *
+ * Purpose: add one EA into ea->ea_entries[]
+ *
+ * Arguments:
+ *
+ *    ea            (rw) pointer to struct ea
+ *    attruname     (r) name of EA
+ *    attrsize      (r) size of ea
+ *    bitmap        (r) bitmap from FP func
+ *
+ * Returns: new number of EA entries, -1 on error
+ *
+ * Effects:
+ *
+ * Grow array ea->ea_entries[]. If ea->ea_entries is still NULL, start allocating.
+ * Otherwise realloc and put entry at the end. Increments ea->ea_count.
+ */
+static int ea_addentry(struct ea * restrict ea,
+                       const char * restrict attruname,
+                       size_t attrsize,
+                       int bitmap)
+{
+    int ea_existed = 0;
+    unsigned int count = 0;
+    void *tmprealloc;
+
+    /* First check if an EA of the requested name already exist */
+    if (ea->ea_count > 0) {
+        while (count < ea->ea_count) {
+            if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) {
+                ea_existed = 1;
+                LOG(log_debug, logtype_afpd, "ea_addentry('%s', bitmap:0x%x): exists", attruname, bitmap);
+                if (bitmap & kXAttrCreate)
+                    /* its like O_CREAT|O_EXCL -> fail */
+                    return -1;
+                (*(ea->ea_entries))[count].ea_size = attrsize;
+                return 0;
+            }
+            count++;
+        }
+    }
+
+    if ((bitmap & kXAttrReplace) && ! ea_existed)
+        /* replace was requested, but EA didn't exist */
+        return -1;
+
+    if (ea->ea_count == 0) {
+        ea->ea_entries = malloc(sizeof(struct ea_entry));
+        if ( ! ea->ea_entries) {
+            LOG(log_error, logtype_afpd, "ea_addentry: OOM");
+            return -1;
+        }
+    } else if (! ea_existed) {
+        tmprealloc = realloc(ea->ea_entries, sizeof(struct ea_entry) * (ea->ea_count + 1));
+        if ( ! tmprealloc) {
+            LOG(log_error, logtype_afpd, "ea_addentry: OOM");
+            return -1;
+        }
+        ea->ea_entries = tmprealloc;
+    }
+
+    /* We've grown the array, now store the entry */
+    (*(ea->ea_entries))[ea->ea_count].ea_size = attrsize;
+    (*(ea->ea_entries))[ea->ea_count].ea_name = strdup(attruname);
+    if ( ! (*(ea->ea_entries))[ea->ea_count].ea_name) {
+        LOG(log_error, logtype_afpd, "ea_addentry: OOM");
+        goto error;
+    }
+    (*(ea->ea_entries))[ea->ea_count].ea_namelen = strlen(attruname);
+
+    ea->ea_count++;
+    return ea->ea_count;
+
+error:
+    if (ea->ea_count == 0 && ea->ea_entries) {
+        /* We just allocated storage but had an error somewhere -> free storage*/
+        free(ea->ea_entries);
+        ea->ea_entries = NULL;
+    }
+    ea->ea_count = 0;
+    return -1;
+}
+
+/*
+ * Function: create_ea_header
+ *
+ * Purpose: create EA header file, only called from ea_open
+ *
+ * Arguments:
+ *
+ *    uname       (r)  filename for which we have to create a header
+ *    ea          (rw) ea handle with already allocated storage pointed to
+ *                     by ea->ea_data
+ *
+ * Returns: fd of open header file on success, -1 on error, errno semantics:
+ *          EEXIST: open with O_CREAT | O_EXCL failed
+ *
+ * Effects:
+ *
+ * Creates EA header file and initialize ea->ea_data buffer.
+ * Possibe race condition with other afpd processes:
+ * we were called because header file didn't exist in eg. ea_open. We then
+ * try to create a file with O_CREAT | O_EXCL, but the whole process in not atomic.
+ * What do we do then? Someone else is in the process of creating the header too, but
+ * it might not have finished it. That means we cant just open, read and use it!
+ * We therefor currently just break with an error.
+ * On return the header file is still r/w locked.
+ */
+static int create_ea_header(const char * restrict uname,
+                            struct ea * restrict ea)
+{
+    int fd = -1, err = 0;
+    char *ptr;
+
+    if ((fd = open(uname, O_RDWR | O_CREAT | O_EXCL, 0666 & ~ea->vol->v_umask)) == -1) {
+        LOG(log_error, logtype_afpd, "ea_create: open race condition with ea header for file: %s", uname);
+        return -1;
+    }
+
+    /* lock it */
+    if ((write_lock(fd, 0, SEEK_SET, 0)) != 0) {
+        LOG(log_error, logtype_afpd, "ea_create: lock race condition with ea header for file: %s", uname);
+        err = -1;
+        goto exit;
+    }
+
+    /* Now init it */
+    ptr = ea->ea_data;
+    *(uint32_t *)ptr = htonl(EA_MAGIC);
+    ptr += EA_MAGIC_LEN;
+    *(uint16_t *)ptr = htons(EA_VERSION);
+    ptr += EA_VERSION_LEN;
+    *(uint16_t *)ptr = 0;       /* count */
+
+    ea->ea_size = EA_HEADER_SIZE;
+    ea->ea_inited = EA_INITED;
+
+exit:
+    if (err != 0) {
+        close(fd);
+        fd = -1;
+    }
+    return fd;
+}
+
+/*
+ * Function: write_ea
+ *
+ * Purpose: write an EA to disk
+ *
+ * Arguments:
+ *
+ *    ea         (r) struct ea handle
+ *    attruname  (r) EA name
+ *    ibuf       (r) buffer with EA content
+ *    attrsize   (r) size of EA
+ *
+ * Returns: 0 on success, -1 on error
+ *
+ * Effects:
+ *
+ * Creates/overwrites EA file.
+ *
+ */
+static int write_ea(const struct ea * restrict ea,
+                    const char * restrict attruname,
+                    const char * restrict ibuf,
+                    size_t attrsize)
+{
+    int fd = -1, ret = AFP_OK;
+    struct stat st;
+    char *eaname;
+
+    if ((eaname = ea_path(ea, attruname, 1)) == NULL) {
+        LOG(log_error, logtype_afpd, "write_ea('%s'): ea_path error", attruname);
+        return AFPERR_MISC;
+    }
+
+    LOG(log_maxdebug, logtype_afpd, "write_ea('%s')", eaname);
+
+    /* Check if it exists, remove if yes*/
+    if ((stat(eaname, &st)) == 0) {
+        if ((unlink(eaname)) != 0) {
+            if (errno == EACCES)
+                return AFPERR_ACCESS;
+            else
+                return AFPERR_MISC;
+        }
+    }
+
+    if ((fd = open(eaname, O_RDWR | O_CREAT | O_EXCL, 0666 & ~ea->vol->v_umask)) == -1) {
+        LOG(log_error, logtype_afpd, "write_ea: open race condition: %s", eaname);
+        return -1;
+    }
+
+    /* lock it */
+    if ((write_lock(fd, 0, SEEK_SET, 0)) != 0) {
+        LOG(log_error, logtype_afpd, "write_ea: open race condition: %s", eaname);
+        ret = -1;
+        goto exit;
+    }
+
+    if (write(fd, ibuf, attrsize) != (ssize_t)attrsize) {
+        LOG(log_error, logtype_afpd, "write_ea('%s'): write: %s", eaname, strerror(errno));
+        ret = -1;
+        goto exit;
+    }
+
+exit:
+    if (fd != -1)
+        close(fd); /* and unlock */
+    return ret;
+}
+
+/*
+ * Function: ea_delentry
+ *
+ * Purpose: delete one EA from ea->ea_entries[]
+ *
+ * Arguments:
+ *
+ *    ea            (rw) pointer to struct ea
+ *    attruname     (r) EA name
+ *
+ * Returns: new number of EA entries, -1 on error
+ *
+ * Effects:
+ *
+ * Remove entry from  ea->ea_entries[]. Decrement ea->ea_count.
+ * Marks it as unused just by freeing name and setting it to NULL.
+ * ea_close and pack_buffer must honor this.
+ */
+static int ea_delentry(struct ea * restrict ea, const char * restrict attruname)
+{
+    int ret = 0;
+    unsigned int count = 0;
+
+    if (ea->ea_count == 0) {
+        LOG(log_error, logtype_afpd, "ea_delentry('%s'): illegal ea_count of 0 on deletion");
+        return -1;
+    }
+
+    while (count < ea->ea_count) {
+        /* search matching EA */
+        if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) {
+            free((*ea->ea_entries)[count].ea_name);
+            (*ea->ea_entries)[count].ea_name = NULL;
+
+            LOG(log_debug, logtype_afpd, "ea_delentry('%s'): deleted no %u/%u",
+                attruname, count + 1, ea->ea_count);
+
+            break;
+        }
+        count++;
+    }
+
+    return ret;
+}
+
+/*
+ * Function: delete_ea_file
+ *
+ * Purpose: delete EA file from disk
+ *
+ * Arguments:
+ *
+ *    ea         (r) struct ea handle
+ *    attruname  (r) EA name
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int delete_ea_file(const struct ea * restrict ea, const char *eaname)
+{
+    int ret = 0;
+    char *eafile;
+    struct stat st;
+
+    if ((eafile = ea_path(ea, eaname, 1)) == NULL) {
+        LOG(log_error, logtype_afpd, "delete_ea_file('%s'): ea_path error", eaname);
+        return -1;
+    }
+
+    /* Check if it exists, remove if yes*/
+    if ((stat(eafile, &st)) == 0) {
+        if ((unlink(eafile)) != 0) {
+            LOG(log_error, logtype_afpd, "delete_ea_file('%s'): unlink: %s",
+                eafile, strerror(errno));
+            ret = -1;
+        } else
+            LOG(log_debug, logtype_afpd, "delete_ea_file('%s'): success", eafile);
+    }
+
+    return ret;
+}
+
+/*************************************************************************************
+ * ea_path, ea_open and ea_close are only global so that dbd can call them
+ *************************************************************************************/
+
+/*
+ * Function: ea_path
+ *
+ * Purpose: return name of ea header filename
+ *
+ * Arguments:
+ *
+ *    ea           (r) ea handle
+ *    eaname       (r) name of EA or NULL
+ *    macname      (r) if != 0 call mtoupath on eaname
+ *
+ * Returns: pointer to name in static buffer, NULL on error
+ *
+ * Effects:
+ *
+ * Calls ad_open, copies buffer, appends "::EA" and if supplied append eanme
+ * Files: "file" -> "file/.AppleDouble/file::EA"
+ * Dirs: "dir" -> "dir/.AppleDouble/.Parent::EA"
+ * "file" with EA "myEA" -> "file/.AppleDouble/file::EA:myEA"
+ */
+char *ea_path(const struct ea * restrict ea, const char * restrict eaname, int macname)
+{
+    char *adname;
+    static char pathbuf[MAXPATHLEN + 1];
+
+    /* get name of a adouble file from uname */
+    adname = ea->vol->ad_path(ea->filename, (ea->ea_flags & EA_DIR) ? ADFLAGS_DIR : 0);
+    /* copy it so we can work with it */
+    strlcpy(pathbuf, adname, MAXPATHLEN + 1);
+    /* append "::EA" */
+    strlcat(pathbuf, "::EA", MAXPATHLEN + 1);
+
+    if (eaname) {
+        strlcat(pathbuf, "::", MAXPATHLEN + 1);
+        if (macname)
+            if ((eaname = mtoupath(ea->vol, eaname)) == NULL)
+                return NULL;
+        strlcat(pathbuf, eaname, MAXPATHLEN + 1);
+    }
+
+    return pathbuf;
+}
+
+/*
+ * Function: ea_open
+ *
+ * Purpose: open EA header file, create if it doesnt exits and called with O_CREATE
+ *
+ * Arguments:
+ *
+ *    vol         (r) current volume
+ *    uname       (r) filename for which we have to open a header
+ *    flags       (r) EA_CREATE: create if it doesn't exist (without it won't be created)
+ *                    EA_RDONLY: open read only
+ *                    EA_RDWR: open read/write
+ *                    Eiterh EA_RDONLY or EA_RDWR MUST be requested
+ *    ea          (w) pointer to a struct ea that we fill
+ *
+ * Returns: 0 on success
+ *         -1 on misc error with errno = EFAULT
+ *         -2 if no EA header exists with errno = ENOENT
+ *
+ * Effects:
+ *
+ * opens header file and stores fd in ea->ea_fd. Size of file is put into ea->ea_size.
+ * number of EAs is stored in ea->ea_count. flags are remembered in ea->ea_flags.
+ * file is either read or write locked depending on the open flags.
+ * When you're done with struct ea you must call ea_close on it.
+ */
+int ea_open(const struct vol * restrict vol,
+            const char * restrict uname,
+            eaflags_t eaflags,
+            struct ea * restrict ea)
+{
+    int ret = 0;
+    char *eaname;
+    struct stat st;
+
+    /* Enforce usage rules! */
+    if ( ! (eaflags & (EA_RDONLY | EA_RDWR))) {
+        LOG(log_error, logtype_afpd, "ea_open: called without EA_RDONLY | EA_RDWR", uname);
+        return -1;
+    }
+
+    /* Set it all to 0 */
+    memset(ea, 0, sizeof(struct ea));
+
+    ea->vol = vol;              /* ea_close needs it */
+    ea->ea_flags = eaflags;
+    ea->dirfd = -1;             /* no *at (cf openat) semantics by default */
+
+    /* Dont care for errors, eg when removing the file is already gone */
+    if (!stat(uname, &st) && S_ISDIR(st.st_mode))
+        ea->ea_flags |=  EA_DIR;
+
+    if ( ! (ea->filename = strdup(uname))) {
+        LOG(log_error, logtype_afpd, "ea_open: OOM");
+        return -1;
+    }
+
+    eaname = ea_path(ea, NULL, 0);
+    LOG(log_maxdebug, logtype_afpd, "ea_open: ea_path: %s", eaname);
+
+    /* Check if it exists, if not create it if EA_CREATE is in eaflags */
+    if ((stat(eaname, &st)) != 0) {
+        if (errno == ENOENT) {
+
+            /* It doesnt exist */
+
+            if ( ! (eaflags & EA_CREATE)) {
+                /* creation was not requested, so return with error */
+                ret = -2;
+                goto exit;
+            }
+
+            /* Now create a header file */
+
+            /* malloc buffer for minimal on disk data */
+            ea->ea_data = malloc(EA_HEADER_SIZE);
+            if (! ea->ea_data) {
+                LOG(log_error, logtype_afpd, "ea_open: OOM");
+                ret = -1;
+                goto exit;
+            }
+
+            /* create it */
+            ea->ea_fd = create_ea_header(eaname, ea);
+            if (ea->ea_fd == -1) {
+                ret = -1;
+                goto exit;
+            }
+
+            return 0;
+
+        } else {/* errno != ENOENT */
+            ret = -1;
+            goto exit;
+        }
+    }
+
+    /* header file exists, so read and parse it */
+
+    /* malloc buffer where we read disk file into */
+    if (st.st_size < EA_HEADER_SIZE) {
+        LOG(log_error, logtype_afpd, "ea_open('%s'): bogus EA header file", eaname);
+        ret = -1;
+        goto exit;
+    }
+    ea->ea_size = st.st_size;
+    ea->ea_data = malloc(st.st_size);
+    if (! ea->ea_data) {
+        LOG(log_error, logtype_afpd, "ea_open: OOM");
+        ret = -1;
+        goto exit;
+    }
+
+    /* Now lock, open and read header file from disk */
+    if ((ea->ea_fd = open(eaname, (ea->ea_flags & EA_RDWR) ? O_RDWR : O_RDONLY)) == -1) {
+        LOG(log_error, logtype_afpd, "ea_open('%s'): error: %s", eaname, strerror(errno));
+        ret = -1;
+        goto exit;
+    }
+
+    /* lock it */
+    if (ea->ea_flags & EA_RDONLY) {
+        /* read lock */
+        if ((read_lock(ea->ea_fd, 0, SEEK_SET, 0)) != 0) {
+            LOG(log_error, logtype_afpd, "ea_open: lock error on  header: %s", eaname);
+            ret = -1;
+            goto exit;
+        }
+    } else {  /* EA_RDWR */
+        /* write lock */
+        if ((write_lock(ea->ea_fd, 0, SEEK_SET, 0)) != 0) {
+            LOG(log_error, logtype_afpd, "ea_open: lock error on  header: %s", eaname);
+            ret = -1;
+            goto exit;
+        }
+    }
+
+    /* read it */
+    if (read(ea->ea_fd, ea->ea_data, ea->ea_size) != (ssize_t)ea->ea_size) {
+        LOG(log_error, logtype_afpd, "ea_open: short read on header: %s", eaname);
+        ret = -1;
+        goto exit;
+    }
+
+    if ((unpack_header(ea)) != 0) {
+        LOG(log_error, logtype_afpd, "ea_open: error unpacking header for: %s", eaname);
+        ret = -1;
+        goto exit;
+    }
+
+exit:
+    switch (ret) {
+    case 0:
+        ea->ea_inited = EA_INITED;
+        break;
+    case -1:
+        errno = EFAULT; /* force some errno distinguishable from ENOENT */
+        /* fall through */
+    case -2:
+        if (ea->ea_data) {
+            free(ea->ea_data);
+            ea->ea_data = NULL;
+        }
+        if (ea->ea_fd) {
+            close(ea->ea_fd);
+            ea->ea_fd = -1;
+        }
+        break;
+    }
+
+    return ret;
+}
+
+/*
+ * Function: ea_openat
+ *
+ * Purpose: openat like wrapper for ea_open, takes a additional file descriptor
+ *
+ * Arguments:
+ *
+ *    vol         (r) current volume
+ *    sfd         (r) openat like file descriptor
+ *    uname       (r) filename for which we have to open a header
+ *    flags       (r) EA_CREATE: create if it doesn't exist (without it won't be created)
+ *                    EA_RDONLY: open read only
+ *                    EA_RDWR: open read/write
+ *                    Eiterh EA_RDONLY or EA_RDWR MUST be requested
+ *    ea          (w) pointer to a struct ea that we fill
+ *
+ * Returns: 0 on success
+ *         -1 on misc error with errno = EFAULT
+ *         -2 if no EA header exists with errno = ENOENT
+ *
+ * Effects:
+ *
+ * opens header file and stores fd in ea->ea_fd. Size of file is put into ea->ea_size.
+ * number of EAs is stored in ea->ea_count. flags are remembered in ea->ea_flags.
+ * file is either read or write locked depending on the open flags.
+ * When you're done with struct ea you must call ea_close on it.
+ */
+int ea_openat(const struct vol * restrict vol,
+              int dirfd,
+              const char * restrict uname,
+              eaflags_t eaflags,
+              struct ea * restrict ea)
+{
+    int ret = 0;
+    int cwdfd = -1;
+
+    if (dirfd != -1) {
+        if (((cwdfd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
+            ret = -1;
+            goto exit;
+        }
+    }
+
+    ret = ea_open(vol, uname, eaflags, ea);
+    ea->dirfd = dirfd;
+
+    if (dirfd != -1) {
+        if (fchdir(cwdfd) != 0) {
+            LOG(log_error, logtype_afpd, "ea_openat: cant chdir back, exiting");
+            exit(EXITERR_SYS);
+        }
+    }
+
+
+exit:
+    if (cwdfd != -1)
+        close(cwdfd);
+
+    return ret;
+
+}
+
+/*
+ * Function: ea_close
+ *
+ * Purpose: flushes and closes an ea handle
+ *
+ * Arguments:
+ *
+ *    ea          (rw) pointer to ea handle
+ *
+ * Returns: 0 on success, -1 on error
+ *
+ * Effects:
+ *
+ * Flushes and then closes and frees all resouces held by ea handle.
+ * Pack data in ea into ea_data, then write ea_data to disk
+ */
+int ea_close(struct ea * restrict ea)
+{
+    int ret = 0; 
+    unsigned int count = 0;
+    char *eaname;
+    struct stat st;
+
+    LOG(log_debug, logtype_afpd, "ea_close('%s')", ea->filename);
+
+    if (ea->ea_inited != EA_INITED) {
+        LOG(log_warning, logtype_afpd, "ea_close('%s'): non initialized ea", ea->filename);
+        return 0;
+    }
+
+    /* pack header and write it to disk if it was opened EA_RDWR*/
+    if (ea->ea_flags & EA_RDWR) {
+        if ((pack_header(ea)) != 0) {
+            LOG(log_error, logtype_afpd, "ea_close: pack header");
+            ret = -1;
+        } else {
+            if (ea->ea_count == 0) {
+                /* Check if EA header exists and remove it */
+                eaname = ea_path(ea, NULL, 0);
+                if ((lstatat(ea->dirfd, eaname, &st)) == 0) {
+                    if ((netatalk_unlinkat(ea->dirfd, eaname)) != 0) {
+                        LOG(log_error, logtype_afpd, "ea_close('%s'): unlink: %s",
+                            eaname, strerror(errno));
+                        ret = -1;
+                    }
+                    else
+                        LOG(log_debug, logtype_afpd, "ea_close(unlink '%s'): success", eaname);
+                } else {
+                    /* stat error */
+                    if (errno != ENOENT) {
+                        LOG(log_error, logtype_afpd, "ea_close('%s'): stat: %s",
+                            eaname, strerror(errno));
+                        ret = -1;
+                    }
+                }
+            } else { /* ea->ea_count > 0 */
+                if ((lseek(ea->ea_fd, 0, SEEK_SET)) == -1) {
+                    LOG(log_error, logtype_afpd, "ea_close: lseek: %s", strerror(errno));
+                    ret = -1;
+                    goto exit;
+                }
+
+                if ((ftruncate(ea->ea_fd, 0)) == -1) {
+                    LOG(log_error, logtype_afpd, "ea_close: ftruncate: %s", strerror(errno));
+                    ret = -1;
+                    goto exit;
+                }
+
+                if (write(ea->ea_fd, ea->ea_data, ea->ea_size) != (ssize_t)ea->ea_size) {
+                    LOG(log_error, logtype_afpd, "ea_close: write: %s", strerror(errno));
+                    ret = -1;
+                }
+            }
+        }
+    }
+
+exit:
+    /* free names */
+    while(count < ea->ea_count) {
+        if ( (*ea->ea_entries)[count].ea_name ) {
+            free((*ea->ea_entries)[count].ea_name);
+            (*ea->ea_entries)[count].ea_name = NULL;
+        }
+        count++;
+    }
+    ea->ea_count = 0;
+
+    if (ea->filename) {
+        free(ea->filename);
+        ea->filename = NULL;
+    }
+
+    if (ea->ea_entries) {
+        free(ea->ea_entries);
+        ea->ea_entries = NULL;
+    }
+
+    if (ea->ea_data) {
+        free(ea->ea_data);
+        ea->ea_data = NULL;
+    }
+    if (ea->ea_fd != -1) {
+        close(ea->ea_fd);       /* also releases the fcntl lock */
+        ea->ea_fd = -1;
+    }
+
+    return 0;
+}
+
+
+
+/************************************************************************************
+ * VFS funcs called from afp_ea* funcs
+ ************************************************************************************/
+
+/*
+ * Function: get_easize
+ *
+ * Purpose: get size of an 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 get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
+{
+    int ret = AFPERR_MISC;
+    unsigned int count = 0;
+    uint32_t uint32;
+    struct ea ea;
+
+    LOG(log_debug, logtype_afpd, "get_easize: file: %s", uname);
+
+    if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) {
+        if (errno != ENOENT)
+            LOG(log_error, logtype_afpd, "get_easize: error calling ea_open for file: %s", uname);
+
+        memset(rbuf, 0, 4);
+        *rbuflen += 4;
+        return ret;
+    }
+
+    while (count < ea.ea_count) {
+        if (strcmp(attruname, (*ea.ea_entries)[count].ea_name) == 0) {
+            uint32 = htonl((*ea.ea_entries)[count].ea_size);
+            memcpy(rbuf, &uint32, 4);
+            *rbuflen += 4;
+            ret = AFP_OK;
+
+            LOG(log_debug, logtype_afpd, "get_easize(\"%s\"): size: %u",
+                attruname, (*ea.ea_entries)[count].ea_size);
+            break;
+        }
+        count++;
+    }
+
+    if ((ea_close(&ea)) != 0) {
+        LOG(log_error, logtype_afpd, "get_easize: error closing ea handle for file: %s", uname);
+        return AFPERR_MISC;
+    }
+
+    return ret;
+}
+
+/*
+ * Function: get_eacontent
+ *
+ * Purpose: copy 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 get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
+{
+    int ret = AFPERR_MISC, fd = -1;
+    unsigned int count = 0;
+    uint32_t uint32;
+    size_t toread;
+    struct ea ea;
+    char *eafile;
+
+    LOG(log_debug, logtype_afpd, "get_eacontent('%s/%s')", uname, attruname);
+
+    if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) {
+        if (errno != ENOENT)
+            LOG(log_error, logtype_afpd, "get_eacontent('%s'): ea_open error", uname);
+        memset(rbuf, 0, 4);
+        *rbuflen += 4;
+        return ret;
+    }
+
+    while (count < ea.ea_count) {
+        if (strcmp(attruname, (*ea.ea_entries)[count].ea_name) == 0) {
+            if ( (eafile = ea_path(&ea, attruname, 1)) == NULL) {
+                ret = AFPERR_MISC;
+                break;
+            }
+
+            if ((fd = open(eafile, O_RDONLY)) == -1) {
+                LOG(log_error, logtype_afpd, "get_eacontent('%s'): open error: %s", uname, strerror(errno));
+                ret = AFPERR_MISC;
+                break;
+            }
+
+            /* Check how much the client wants, give him what we think is right */
+            maxreply -= MAX_REPLY_EXTRA_BYTES;
+            if (maxreply > MAX_EA_SIZE)
+                maxreply = MAX_EA_SIZE;
+            toread = (maxreply < (*ea.ea_entries)[count].ea_size) ? maxreply : (*ea.ea_entries)[count].ea_size;
+            LOG(log_debug, logtype_afpd, "get_eacontent('%s'): sending %u bytes", attruname, toread);
+
+            /* Put length of EA data in reply buffer */
+            uint32 = htonl(toread);
+            memcpy(rbuf, &uint32, 4);
+            rbuf += 4;
+            *rbuflen += 4;
+
+            if (read(fd, rbuf, toread) != (ssize_t)toread) {
+                LOG(log_error, logtype_afpd, "get_eacontent('%s/%s'): short read", uname, attruname);
+                close(fd);
+                ret = AFPERR_MISC;
+                break;
+            }
+            *rbuflen += toread;
+            close(fd);
+
+            ret = AFP_OK;
+            break;
+        }
+        count++;
+    }
+
+    if ((ea_close(&ea)) != 0) {
+        LOG(log_error, logtype_afpd, "get_eacontent('%s'): error closing ea handle", uname);
+        return AFPERR_MISC;
+    }
+
+    return ret;
+
+}
+
+/*
+ * Function: list_eas
+ *
+ * Purpose: copy names of EAs 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 *buflen accordingly.
+ */
+int list_eas(VFS_FUNC_ARGS_EA_LIST)
+{
+    unsigned int count = 0;
+    int attrbuflen = *buflen, ret = AFP_OK, len;
+    char *buf = attrnamebuf;
+    struct ea ea;
+
+    LOG(log_debug, logtype_afpd, "list_eas: file: %s", uname);
+
+    if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) {
+        if (errno != ENOENT) {
+            LOG(log_error, logtype_afpd, "list_eas: error calling ea_open for file: %s", uname);
+            return AFPERR_MISC;
+        }
+        else
+            return AFP_OK;
+    }
+
+    while (count < ea.ea_count) {
+        /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
+        if ( ( len = convert_string(vol->v_volcharset,
+                                    CH_UTF8_MAC, 
+                                    (*ea.ea_entries)[count].ea_name,
+                                    (*ea.ea_entries)[count].ea_namelen,
+                                    buf + attrbuflen,
+                                    255))
+             <= 0 ) {
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+        if (len == 255)
+            /* convert_string didn't 0-terminate */
+            attrnamebuf[attrbuflen + 255] = 0;
+
+        LOG(log_debug7, logtype_afpd, "list_eas(%s): EA: %s",
+            uname, (*ea.ea_entries)[count].ea_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, "list_eas(%s): running out of buffer for EA names", uname);
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+        count++;
+    }
+
+exit:
+    *buflen = attrbuflen;
+
+    if ((ea_close(&ea)) != 0) {
+        LOG(log_error, logtype_afpd, "list_eas: error closing ea handle for file: %s", uname);
+        return AFPERR_MISC;
+    }
+
+    return ret;
+}
+
+/*
+ * Function: 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 set_ea(VFS_FUNC_ARGS_EA_SET)
+{
+    int ret = AFP_OK;
+    struct ea ea;
+
+    LOG(log_debug, logtype_afpd, "set_ea: file: %s", uname);
+
+    if ((ea_open(vol, uname, EA_CREATE | EA_RDWR, &ea)) != 0) {
+        LOG(log_error, logtype_afpd, "set_ea('%s'): ea_open error", uname);
+        return AFPERR_MISC;
+    }
+
+    if ((ea_addentry(&ea, attruname, attrsize, oflag)) == -1) {
+        LOG(log_error, logtype_afpd, "set_ea('%s'): ea_addentry error", uname);
+        ret = AFPERR_MISC;
+        goto exit;
+    }
+
+    if ((write_ea(&ea, attruname, ibuf, attrsize)) != 0) {
+        LOG(log_error, logtype_afpd, "set_ea('%s'): write_ea error", uname);
+        ret = AFPERR_MISC;
+        goto exit;
+    }
+
+exit:
+    if ((ea_close(&ea)) != 0) {
+        LOG(log_error, logtype_afpd, "set_ea('%s'): ea_close error", uname);
+        ret = AFPERR_MISC;
+        goto exit;
+    }
+
+    return ret;
+}
+
+/*
+ * Function: remove_ea
+ *
+ * Purpose: remove a EA from a file
+ *
+ * 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 remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
+{
+    int ret = AFP_OK;
+    struct ea ea;
+
+    LOG(log_debug, logtype_afpd, "remove_ea('%s/%s')", uname, attruname);
+
+    if ((ea_open(vol, uname, EA_RDWR, &ea)) != 0) {
+        LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_open error", uname);
+        return AFPERR_MISC;
+    }
+
+    if ((ea_delentry(&ea, attruname)) == -1) {
+        LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_delentry error", uname);
+        ret = AFPERR_MISC;
+        goto exit;
+    }
+
+    if ((delete_ea_file(&ea, attruname)) != 0) {
+        LOG(log_error, logtype_afpd, "remove_ea('%s'): delete_ea error", uname);
+        ret = AFPERR_MISC;
+        goto exit;
+    }
+
+exit:
+    if ((ea_close(&ea)) != 0) {
+        LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_close error", uname);
+        ret = AFPERR_MISC;
+        goto exit;
+    }
+
+    return ret;
+}
+
+/******************************************************************************************
+ * EA VFS funcs that deal with file/dir cp/mv/rm
+ ******************************************************************************************/
+
+int ea_deletefile(VFS_FUNC_ARGS_DELETEFILE)
+{
+    unsigned int count = 0;
+    int ret = AFP_OK;
+    int cwd = -1;
+    struct ea ea;
+
+    LOG(log_debug, logtype_afpd, "ea_deletefile('%s')", file);
+
+    /* Open EA stuff */
+    if ((ea_openat(vol, dirfd, file, EA_RDWR, &ea)) != 0) {
+        if (errno == ENOENT)
+            /* no EA files, nothing to do */
+            return AFP_OK;
+        else {
+            LOG(log_error, logtype_afpd, "ea_deletefile('%s'): error calling ea_open", file);
+            return AFPERR_MISC;
+        }
+    }
+
+    if (dirfd != -1) {
+        if (((cwd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+    }
+
+    while (count < ea.ea_count) {
+        if ((delete_ea_file(&ea, (*ea.ea_entries)[count].ea_name)) != 0) {
+            ret = AFPERR_MISC;
+            continue;
+        }
+        free((*ea.ea_entries)[count].ea_name);
+        (*ea.ea_entries)[count].ea_name = NULL;
+        count++;
+    }
+
+    /* ea_close removes the EA header file for us because all names are NULL */
+    if ((ea_close(&ea)) != 0) {
+        LOG(log_error, logtype_afpd, "ea_deletefile('%s'): error closing ea handle", file);
+        ret = AFPERR_MISC;
+    }
+
+    if (dirfd != -1 && fchdir(cwd) != 0) {
+        LOG(log_error, logtype_afpd, "ea_deletefile: cant chdir back. exit!");
+        exit(EXITERR_SYS);
+    }
+
+exit:
+    if (cwd != -1)
+        close(cwd);
+
+    return ret;
+}
+
+int ea_renamefile(VFS_FUNC_ARGS_RENAMEFILE)
+{
+    unsigned int count = 0;
+    int    ret = AFP_OK;
+    size_t easize;
+    char   srceapath[ MAXPATHLEN + 1];
+    char   *eapath;
+    char   *eaname;
+    struct ea srcea;
+    struct ea dstea;
+    struct adouble ad;
+
+    LOG(log_debug, logtype_afpd, "ea_renamefile('%s'/'%s')", src, dst);
+            
+
+    /* Open EA stuff */
+    if ((ea_openat(vol, dirfd, src, EA_RDWR, &srcea)) != 0) {
+        if (errno == ENOENT)
+            /* no EA files, nothing to do */
+            return AFP_OK;
+        else {
+            LOG(log_error, logtype_afpd, "ea_renamefile('%s'/'%s'): ea_open error: '%s'", src, dst, src);
+            return AFPERR_MISC;
+        }
+    }
+
+    if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
+        if (errno == ENOENT) {
+            /* Possibly the .AppleDouble folder didn't exist, we create it and try again */
+            ad_init(&ad, vol->v_adouble, vol->v_ad_options); 
+            if ((ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) != 0) {
+                LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): ad_open error: '%s'", src, dst, dst);
+                ret = AFPERR_MISC;
+                goto exit;
+            }
+            ad_close(&ad, ADFLAGS_HF);
+            if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
+                ret = AFPERR_MISC;
+                goto exit;
+            }
+        }
+    }
+
+    /* Loop through all EAs: */
+    while (count < srcea.ea_count) {
+        /* Move EA */
+        eaname = (*srcea.ea_entries)[count].ea_name;
+        easize = (*srcea.ea_entries)[count].ea_size;
+
+        /* Build src and dst paths for rename() */
+        if ((eapath = ea_path(&srcea, eaname, 1)) == NULL) {
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+        strcpy(srceapath, eapath);
+        if ((eapath = ea_path(&dstea, eaname, 1)) == NULL) {
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+
+        LOG(log_maxdebug, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
+            src, dst, srceapath, eapath);
+
+        /* Add EA to dstea */
+        if ((ea_addentry(&dstea, eaname, easize, 0)) == -1) {
+            LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
+                src, dst, srceapath, eapath);
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+
+        /* Remove EA entry from srcea */
+        if ((ea_delentry(&srcea, eaname)) == -1) {
+            LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
+                src, dst, srceapath, eapath);
+            ea_delentry(&dstea, eaname);
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+
+        /* Now rename the EA */
+        if ((unix_rename(dirfd, srceapath, -1, eapath)) < 0) {
+            LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
+                src, dst, srceapath, eapath);
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+
+        count++;
+    }
+
+
+exit:
+    ea_close(&srcea);
+    ea_close(&dstea);
+       return ret;
+}
+
+int ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
+{
+    unsigned int count = 0;
+    int    ret = AFP_OK;
+    size_t easize;
+    char   srceapath[ MAXPATHLEN + 1];
+    char   *eapath;
+    char   *eaname;
+    struct ea srcea;
+    struct ea dstea;
+    struct adouble ad;
+
+    LOG(log_debug, logtype_afpd, "ea_copyfile('%s'/'%s')", src, dst);
+
+    /* Open EA stuff */
+    if ((ea_openat(vol, sfd, src, EA_RDWR, &srcea)) != 0) {
+        if (errno == ENOENT)
+            /* no EA files, nothing to do */
+            return AFP_OK;
+        else {
+            LOG(log_error, logtype_afpd, "ea_copyfile('%s'/'%s'): ea_open error: '%s'", src, dst, src);
+            return AFPERR_MISC;
+        }
+    }
+
+    if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
+        if (errno == ENOENT) {
+            /* Possibly the .AppleDouble folder didn't exist, we create it and try again */
+            ad_init(&ad, vol->v_adouble, vol->v_ad_options); 
+            if ((ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) != 0) {
+                LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): ad_open error: '%s'", src, dst, dst);
+                ret = AFPERR_MISC;
+                goto exit;
+            }
+            ad_close(&ad, ADFLAGS_HF);
+            if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
+                ret = AFPERR_MISC;
+                goto exit;
+            }
+        }
+    }
+
+    /* Loop through all EAs: */
+    while (count < srcea.ea_count) {
+        /* Copy EA */
+        eaname = (*srcea.ea_entries)[count].ea_name;
+        easize = (*srcea.ea_entries)[count].ea_size;
+
+        /* Build src and dst paths for copy_file() */
+        if ((eapath = ea_path(&srcea, eaname, 1)) == NULL) {
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+        strcpy(srceapath, eapath);
+        if ((eapath = ea_path(&dstea, eaname, 1)) == NULL) {
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+
+        LOG(log_maxdebug, logtype_afpd, "ea_copyfile('%s/%s'): copying EA '%s' to '%s'",
+            src, dst, srceapath, eapath);
+
+        /* Add EA to dstea */
+        if ((ea_addentry(&dstea, eaname, easize, 0)) == -1) {
+            LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): ea_addentry('%s') error",
+                src, dst, eaname);
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+
+        /* Now copy the EA */
+        if ((copy_file(sfd, srceapath, eapath, (0666 & ~vol->v_umask))) < 0) {
+            LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): copying EA '%s' to '%s'",
+                src, dst, srceapath, eapath);
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+
+        count++;
+    }
+
+exit:
+    ea_close(&srcea);
+    ea_close(&dstea);
+       return ret;
+}
+
+int ea_chown(VFS_FUNC_ARGS_CHOWN)
+{
+
+    unsigned int count = 0;
+    int ret = AFP_OK;
+    char *eaname;
+    struct ea ea;
+
+    LOG(log_debug, logtype_afpd, "ea_chown('%s')", path);
+    /* Open EA stuff */
+    if ((ea_open(vol, path, EA_RDWR, &ea)) != 0) {
+        if (errno == ENOENT)
+            /* no EA files, nothing to do */
+            return AFP_OK;
+        else {
+            LOG(log_error, logtype_afpd, "ea_chown('%s'): error calling ea_open", path);
+            return AFPERR_MISC;
+        }
+    }
+
+    if ((lchown(ea_path(&ea, NULL, 0), uid, gid)) != 0) {
+        switch (errno) {
+        case EPERM:
+        case EACCES:
+            ret = AFPERR_ACCESS;
+            goto exit;
+        default:
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+    }
+
+    while (count < ea.ea_count) {
+        if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 1)) == NULL) {
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+        if ((lchown(eaname, uid, gid)) != 0) {
+            switch (errno) {
+            case EPERM:
+            case EACCES:
+                ret = AFPERR_ACCESS;
+                goto exit;
+            default:
+                ret = AFPERR_MISC;
+                goto exit;
+            }
+            continue;
+        }
+
+        count++;
+    }
+
+exit:
+    if ((ea_close(&ea)) != 0) {
+        LOG(log_error, logtype_afpd, "ea_chown('%s'): error closing ea handle", path);
+        return AFPERR_MISC;
+    }
+
+    return ret;
+}
+
+int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE)
+{
+
+    unsigned int count = 0;
+    int ret = AFP_OK;
+    const char *eaname;
+    struct ea ea;
+
+    LOG(log_debug, logtype_afpd, "ea_chmod_file('%s')", name);
+    /* Open EA stuff */
+    if ((ea_open(vol, name, EA_RDWR, &ea)) != 0) {
+        if (errno == ENOENT)
+            /* no EA files, nothing to do */
+            return AFP_OK;
+        else
+            return AFPERR_MISC;
+    }
+
+    /* Set mode on EA header file */
+    if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) {
+        LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno));
+        switch (errno) {
+        case EPERM:
+        case EACCES:
+            ret = AFPERR_ACCESS;
+            goto exit;
+        default:
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+    }
+
+    /* Set mode on EA files */
+    while (count < ea.ea_count) {
+        if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 1)) == NULL) {
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+        if ((setfilmode(eaname, ea_mode(mode), NULL, vol->v_umask)) != 0) {
+            LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", eaname, strerror(errno));
+            switch (errno) {
+            case EPERM:
+            case EACCES:
+                ret = AFPERR_ACCESS;
+                goto exit;
+            default:
+                ret = AFPERR_MISC;
+                goto exit;
+            }
+            continue;
+        }
+
+        count++;
+    }
+
+exit:
+    if ((ea_close(&ea)) != 0) {
+        LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): error closing ea handle", name);
+        return AFPERR_MISC;
+    }
+
+    return ret;
+}
+
+int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE)
+{
+
+    int ret = AFP_OK;
+    unsigned int count = 0;
+    uid_t uid;
+    const char *eaname;
+    const char *eaname_safe = NULL;
+    struct ea ea;
+
+    LOG(log_debug, logtype_afpd, "ea_chmod_dir('%s')", name);
+    /* .AppleDouble already might be inaccesible, so we must run as id 0 */
+    uid = geteuid();
+    if (seteuid(0)) {
+        LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): seteuid: %s", name, strerror(errno));
+        return AFPERR_MISC;
+    }
+
+    /* Open EA stuff */
+    if ((ea_open(vol, name, EA_RDWR, &ea)) != 0) {
+        /* ENOENT --> no EA files, nothing to do */
+        if (errno != ENOENT)
+            ret = AFPERR_MISC;
+        if (seteuid(uid) < 0) {
+            LOG(log_error, logtype_afpd, "can't seteuid back: %s", strerror(errno));
+            exit(EXITERR_SYS);
+        }
+        return ret;
+    }
+
+    /* Set mode on EA header */
+    if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) {
+        LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno));
+        switch (errno) {
+        case EPERM:
+        case EACCES:
+            ret = AFPERR_ACCESS;
+            goto exit;
+        default:
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+    }
+
+    /* Set mode on EA files */
+    while (count < ea.ea_count) {
+        eaname = (*ea.ea_entries)[count].ea_name;
+        /*
+         * Be careful with EA names from the EA header!
+         * Eg NFS users might have access to them, can inject paths using ../ or /.....
+         * FIXME:
+         * Until the EA code escapes / in EA name requests from the client, these therefor wont work.
+         */
+        if ((eaname_safe = strrchr(eaname, '/'))) {
+            LOG(log_warning, logtype_afpd, "ea_chmod_dir('%s'): contains a slash", eaname);
+            eaname = eaname_safe;
+        }
+        if ((eaname = ea_path(&ea, eaname, 1)) == NULL) {
+            ret = AFPERR_MISC;
+            goto exit;
+        }
+        if ((setfilmode(eaname, ea_mode(mode), NULL, vol->v_umask)) != 0) {
+            LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", eaname, strerror(errno));
+            switch (errno) {
+            case EPERM:
+            case EACCES:
+                ret = AFPERR_ACCESS;
+                goto exit;
+            default:
+                ret = AFPERR_MISC;
+                goto exit;
+            }
+            continue;
+        }
+
+        count++;
+    }
+
+exit:
+    if (seteuid(uid) < 0) {
+        LOG(log_error, logtype_afpd, "can't seteuid back: %s", strerror(errno));
+        exit(EXITERR_SYS);
+    }
+
+    if ((ea_close(&ea)) != 0) {
+        LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): error closing ea handle", name);
+        return AFPERR_MISC;
+    }
+
+    return ret;
+}
index a4e35a90540d0454c8e2810429d338cca96da46c..2b1879a5efe9254358736c6b0c9c66f4cae19300 100644 (file)
@@ -1,5 +1,4 @@
 /*
-  $Id: ea_sys.c,v 1.8 2010-04-13 08:05:06 franklahm Exp $
   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
 #include <fcntl.h>
 #include <dirent.h>
 
-#if HAVE_ATTR_XATTR_H
-#include <attr/xattr.h>
-#elif HAVE_SYS_XATTR_H
-#include <sys/xattr.h>
-#endif
-
-#ifdef HAVE_SYS_EA_H
-#include <sys/ea.h>
-#endif
-
-#ifdef HAVE_SYS_EXTATTR_H
-#include <sys/extattr.h>
-#endif
-
 #include <atalk/adouble.h>
 #include <atalk/ea.h>
 #include <atalk/afp.h>
 #include <atalk/unix.h>
 #include <atalk/compat.h>
 
-#ifndef ENOATTR
-#define ENOATTR ENODATA
-#endif
-
-
 /**********************************************************************************
  * EA VFS funcs for storing EAs in nativa filesystem EAs
  **********************************************************************************/
diff --git a/libatalk/vfs/extattr.c b/libatalk/vfs/extattr.c
new file mode 100644 (file)
index 0000000..ee2636b
--- /dev/null
@@ -0,0 +1,873 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Samba system utilities
+   Copyright (C) Andrew Tridgell 1992-1998
+   Copyright (C) Jeremy Allison  1998-2005
+   Copyright (C) Timur Bakeyev        2005
+   Copyright (C) Bjoern Jacke    2006-2007
+   
+   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.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   
+   sys_copyxattr modified from LGPL2.1 libattr copyright
+   Copyright (C) 2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
+   Copyright (C) 2001 Andreas Gruenbacher.
+      
+   Samba 3.0.28, modified for netatalk.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#if HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#elif HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
+
+#ifdef HAVE_SYS_EA_H
+#include <sys/ea.h>
+#endif
+
+#ifdef HAVE_ATTROPEN
+
+#include <dirent.h>
+#endif
+
+#ifdef HAVE_SYS_EXTATTR_H
+#include <sys/extattr.h>
+#endif
+
+#include <atalk/adouble.h>
+#include <atalk/util.h>
+#include <atalk/logger.h>
+#include <atalk/ea.h>
+
+/******** Solaris EA helper function prototypes ********/
+#ifdef HAVE_ATTROPEN
+#define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
+static int solaris_write_xattr(int attrfd, const char *value, size_t size);
+static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
+static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
+static int solaris_unlinkat(int attrdirfd, const char *name);
+static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
+static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
+#endif
+
+/**************************************************************************
+ Wrappers for extented attribute calls. Based on the Linux package with
+ support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
+****************************************************************************/
+static char attr_name[256 +5] = "user.";
+
+static const char *prefix(const char *uname)
+{
+#if defined(HAVE_ATTROPEN)
+       return uname;
+#else
+       strlcpy(attr_name +5, uname, 256);
+       return attr_name;
+#endif
+}
+
+ssize_t sys_getxattr (const char *path, const char *uname, void *value, size_t size)
+{
+       const char *name = prefix(uname);
+
+#if defined(HAVE_GETXATTR)
+#ifndef XATTR_ADD_OPT
+       return getxattr(path, name, value, size);
+#else
+       int options = 0;
+       return getxattr(path, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_GETEA)
+       return getea(path, name, value, size);
+#elif defined(HAVE_EXTATTR_GET_FILE)
+       ssize_t retval;
+       /*
+        * The BSD implementation has a nasty habit of silently truncating
+        * the returned value to the size of the buffer, so we have to check
+        * that the buffer is large enough to fit the returned value.
+        */
+       if((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
+        if (size == 0)
+            /* size == 0 means only return size */
+            return retval;
+               if (retval > size) {
+                       errno = ERANGE;
+                       return -1;
+               }
+               if ((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
+                       return retval;
+       }
+
+       LOG(log_maxdebug, logtype_default, "sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno));
+       return -1;
+#elif defined(HAVE_ATTR_GET)
+       int retval, flags = 0;
+       int valuelength = (int)size;
+       char *attrname = strchr(name,'.') + 1;
+       
+       if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+       retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
+
+       return retval ? retval : valuelength;
+#elif defined(HAVE_ATTROPEN)
+       ssize_t ret = -1;
+       int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
+       if (attrfd >= 0) {
+               ret = solaris_read_xattr(attrfd, value, size);
+               close(attrfd);
+       }
+       return ret;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+ssize_t sys_fgetxattr (int filedes, const char *uname, void *value, size_t size)
+{
+    const char *name = prefix(uname);
+
+#if defined(HAVE_FGETXATTR)
+#ifndef XATTR_ADD_OPT
+    return fgetxattr(filedes, name, value, size);
+#else
+    int options = 0;
+    return fgetxattr(filedes, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_FGETEA)
+    return fgetea(filedes, name, value, size);
+#elif defined(HAVE_EXTATTR_GET_FD)
+    char *s;
+    ssize_t retval;
+    int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
+        EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+    const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+
+    if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
+        if(retval > size) {
+            errno = ERANGE;
+            return -1;
+        }
+        if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
+            return retval;
+    }
+
+    LOG(log_debug, logtype_default, "sys_fgetxattr: extattr_get_fd(): %s",
+        strerror(errno)));
+    return -1;
+#elif defined(HAVE_ATTR_GETF)
+    int retval, flags = 0;
+    int valuelength = (int)size;
+    char *attrname = strchr(name,'.') + 1;
+
+    if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+    retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
+
+    return retval ? retval : valuelength;
+#elif defined(HAVE_ATTROPEN)
+    ssize_t ret = -1;
+    int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
+    if (attrfd >= 0) {
+        ret = solaris_read_xattr(attrfd, value, size);
+        close(attrfd);
+    }
+    return ret;
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+ssize_t sys_lgetxattr (const char *path, const char *uname, void *value, size_t size)
+{
+       const char *name = prefix(uname);
+
+#if defined(HAVE_LGETXATTR)
+       return lgetxattr(path, name, value, size);
+#elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
+       int options = XATTR_NOFOLLOW;
+       return getxattr(path, name, value, size, 0, options);
+#elif defined(HAVE_LGETEA)
+       return lgetea(path, name, value, size);
+#elif defined(HAVE_EXTATTR_GET_LINK)
+       ssize_t retval;
+       if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
+               if(retval > size) {
+                       errno = ERANGE;
+                       return -1;
+               }
+               if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
+                       return retval;
+       }
+       
+       LOG(log_maxdebug, logtype_default, "sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno));
+       return -1;
+#elif defined(HAVE_ATTR_GET)
+       int retval, flags = ATTR_DONTFOLLOW;
+       int valuelength = (int)size;
+       char *attrname = strchr(name,'.') + 1;
+       
+       if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+       retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
+
+       return retval ? retval : valuelength;
+#elif defined(HAVE_ATTROPEN)
+       ssize_t ret = -1;
+       int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
+       if (attrfd >= 0) {
+               ret = solaris_read_xattr(attrfd, value, size);
+               close(attrfd);
+       }
+       return ret;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+#if defined(HAVE_EXTATTR_LIST_FILE)
+
+#define EXTATTR_PREFIX(s)      (s), (sizeof((s))-1)
+
+static struct {
+        int space;
+       const char *name;
+       size_t len;
+} 
+extattr[] = {
+       { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("") },
+        { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("") },
+};
+
+typedef union {
+       const char *path;
+       int filedes;
+} extattr_arg;
+
+static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
+{
+       ssize_t list_size;
+       int i, len;
+
+    switch(type) {
+#if defined(HAVE_EXTATTR_LIST_FILE)
+    case 0:
+        list_size = extattr_list_file(arg.path, EXTATTR_NAMESPACE_USER, list, size);
+        break;
+#endif
+#if defined(HAVE_EXTATTR_LIST_LINK)
+    case 1:
+        list_size = extattr_list_link(arg.path, EXTATTR_NAMESPACE_USER, list, size);
+        break;
+#endif
+#if defined(HAVE_EXTATTR_LIST_FD)
+    case 2:
+        list_size = extattr_list_fd(arg.filedes, EXTATTR_NAMESPACE_USER, list, size);
+        break;
+#endif
+    default:
+        errno = ENOSYS;
+        return -1;
+    }
+
+    /* Some error happend. Errno should be set by the previous call */
+    if(list_size < 0)
+        return -1;
+
+    /* No attributes */
+    if(list_size == 0)
+        return 0;
+
+    /* XXX: Call with an empty buffer may be used to calculate
+       necessary buffer size. Unfortunately, we can't say, how
+       many attributes were returned, so here is the potential
+       problem with the emulation.
+    */
+    if(list == NULL)
+        return list_size;
+
+    /* Buffer is too small to fit the results */
+    if(list_size > size) {
+        errno = ERANGE;
+        return -1;
+    }
+
+    /* Convert from pascal strings to C strings */
+    len = list[0];
+    memmove(list, list + 1, list_size);
+
+    for(i = len; i < list_size; ) {
+        LOG(log_maxdebug, logtype_afpd, "len: %d, i: %d", len, i);
+
+        len = list[i];
+        list[i] = '\0';
+        i += len + 1;
+    }
+
+       return list_size;
+}
+
+#endif
+
+#if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
+static char attr_buffer[ATTR_MAX_VALUELEN];
+
+static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
+{
+       int retval = 0, index;
+       attrlist_cursor_t *cursor = 0;
+       int total_size = 0;
+       attrlist_t * al = (attrlist_t *)attr_buffer;
+       attrlist_ent_t *ae;
+       size_t ent_size, left = size;
+       char *bp = list;
+
+       while (True) {
+           if (filedes)
+               retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+           else
+               retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+           if (retval) break;
+           for (index = 0; index < al->al_count; index++) {
+               ae = ATTR_ENTRY(attr_buffer, index);
+               ent_size = strlen(ae->a_name) + sizeof("user.");
+               if (left >= ent_size) {
+                   strncpy(bp, "user.", sizeof("user."));
+                   strncat(bp, ae->a_name, ent_size - sizeof("user."));
+                   bp += ent_size;
+                   left -= ent_size;
+               } else if (size) {
+                   errno = ERANGE;
+                   retval = -1;
+                   break;
+               }
+               total_size += ent_size;
+           }
+           if (al->al_more == 0) break;
+       }
+       if (retval == 0) {
+           flags |= ATTR_ROOT;
+           cursor = 0;
+           while (True) {
+               if (filedes)
+                   retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+               else
+                   retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+               if (retval) break;
+               for (index = 0; index < al->al_count; index++) {
+                   ae = ATTR_ENTRY(attr_buffer, index);
+                   ent_size = strlen(ae->a_name) + sizeof("system.");
+                   if (left >= ent_size) {
+                       strncpy(bp, "system.", sizeof("system."));
+                       strncat(bp, ae->a_name, ent_size - sizeof("system."));
+                       bp += ent_size;
+                       left -= ent_size;
+                   } else if (size) {
+                       errno = ERANGE;
+                       retval = -1;
+                       break;
+                   }
+                   total_size += ent_size;
+               }
+               if (al->al_more == 0) break;
+           }
+       }
+       return (ssize_t)(retval ? retval : total_size);
+}
+
+#endif
+
+#if defined(HAVE_LISTXATTR)
+static ssize_t remove_user(ssize_t ret, char *list, size_t size)
+{
+       size_t len;
+       char *ptr;
+       char *ptr1;
+       ssize_t ptrsize;
+       
+       if (ret <= 0 || size == 0)
+               return ret;
+       ptrsize = ret;
+       ptr = ptr1 = list;
+       while (ptrsize > 0) {
+               len = strlen(ptr1) +1;
+               ptrsize -= len;
+               if (strncmp(ptr1, "user.",5)) {
+                       ptr1 += len;
+                       continue;
+               }
+               memmove(ptr, ptr1 +5, len -5);
+               ptr += len -5;
+               ptr1 += len;
+       }
+       return ptr -list;
+}
+#endif
+
+ssize_t sys_listxattr (const char *path, char *list, size_t size)
+{
+#if defined(HAVE_LISTXATTR)
+       ssize_t ret;
+
+#ifndef XATTR_ADD_OPT
+       ret = listxattr(path, list, size);
+#else
+       int options = 0;
+       ret = listxattr(path, list, size, options);
+#endif
+       return remove_user(ret, list, size);
+
+#elif defined(HAVE_LISTEA)
+       return listea(path, list, size);
+#elif defined(HAVE_EXTATTR_LIST_FILE)
+       extattr_arg arg;
+       arg.path = path;
+       return bsd_attr_list(0, arg, list, size);
+#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
+       return irix_attr_list(path, 0, list, size, 0);
+#elif defined(HAVE_ATTROPEN)
+       ssize_t ret = -1;
+       int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
+       if (attrdirfd >= 0) {
+               ret = solaris_list_xattr(attrdirfd, list, size);
+               close(attrdirfd);
+       }
+       return ret;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+ssize_t sys_llistxattr (const char *path, char *list, size_t size)
+{
+#if defined(HAVE_LLISTXATTR)
+       ssize_t ret;
+
+       ret = llistxattr(path, list, size);
+       return remove_user(ret, list, size);
+#elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
+       ssize_t ret;
+       int options = XATTR_NOFOLLOW;
+
+       ret = listxattr(path, list, size, options);
+       return remove_user(ret, list, size);
+
+#elif defined(HAVE_LLISTEA)
+       return llistea(path, list, size);
+#elif defined(HAVE_EXTATTR_LIST_LINK)
+       extattr_arg arg;
+       arg.path = path;
+       return bsd_attr_list(1, arg, list, size);
+#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
+       return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
+#elif defined(HAVE_ATTROPEN)
+       ssize_t ret = -1;
+       int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
+       if (attrdirfd >= 0) {
+               ret = solaris_list_xattr(attrdirfd, list, size);
+               close(attrdirfd);
+       }
+       return ret;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+int sys_removexattr (const char *path, const char *uname)
+{
+       const char *name = prefix(uname);
+#if defined(HAVE_REMOVEXATTR)
+#ifndef XATTR_ADD_OPT
+       return removexattr(path, name);
+#else
+       int options = 0;
+       return removexattr(path, name, options);
+#endif
+#elif defined(HAVE_REMOVEEA)
+       return removeea(path, name);
+#elif defined(HAVE_EXTATTR_DELETE_FILE)
+       return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, uname);
+#elif defined(HAVE_ATTR_REMOVE)
+       int flags = 0;
+       char *attrname = strchr(name,'.') + 1;
+       
+       if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+       return attr_remove(path, attrname, flags);
+#elif defined(HAVE_ATTROPEN)
+       int ret = -1;
+       int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
+       if (attrdirfd >= 0) {
+               ret = solaris_unlinkat(attrdirfd, name);
+               close(attrdirfd);
+       }
+       return ret;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+int sys_lremovexattr (const char *path, const char *uname)
+{
+       const char *name = prefix(uname);
+#if defined(HAVE_LREMOVEXATTR)
+       return lremovexattr(path, name);
+#elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
+       int options = XATTR_NOFOLLOW;
+       return removexattr(path, name, options);
+#elif defined(HAVE_LREMOVEEA)
+       return lremoveea(path, name);
+#elif defined(HAVE_EXTATTR_DELETE_LINK)
+       return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, uname);
+#elif defined(HAVE_ATTR_REMOVE)
+       int flags = ATTR_DONTFOLLOW;
+       char *attrname = strchr(name,'.') + 1;
+       
+       if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+       return attr_remove(path, attrname, flags);
+#elif defined(HAVE_ATTROPEN)
+       int ret = -1;
+       int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
+       if (attrdirfd >= 0) {
+               ret = solaris_unlinkat(attrdirfd, name);
+               close(attrdirfd);
+       }
+       return ret;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+int sys_setxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
+{
+       const char *name = prefix(uname);
+#if defined(HAVE_SETXATTR)
+#ifndef XATTR_ADD_OPT
+       return setxattr(path, name, value, size, flags);
+#else
+       int options = 0;
+       return setxattr(path, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_SETEA)
+       return setea(path, name, value, size, flags);
+#elif defined(HAVE_EXTATTR_SET_FILE)
+       int retval = 0;
+       if (flags) {
+               /* Check attribute existence */
+               retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
+               if (retval < 0) {
+                       /* REPLACE attribute, that doesn't exist */
+                       if (flags & XATTR_REPLACE && errno == ENOATTR) {
+                               errno = ENOATTR;
+                               return -1;
+                       }
+                       /* Ignore other errors */
+               }
+               else {
+                       /* CREATE attribute, that already exists */
+                       if (flags & XATTR_CREATE) {
+                               errno = EEXIST;
+                               return -1;
+                       }
+               }
+       }
+       retval = extattr_set_file(path, EXTATTR_NAMESPACE_USER, uname, value, size);
+       return (retval < 0) ? -1 : 0;
+#elif defined(HAVE_ATTR_SET)
+       int myflags = 0;
+       char *attrname = strchr(name,'.') + 1;
+       
+       if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
+       if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
+       if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
+
+       return attr_set(path, attrname, (const char *)value, size, myflags);
+#elif defined(HAVE_ATTROPEN)
+       int ret = -1;
+       int myflags = O_RDWR;
+       int attrfd;
+       if (flags & XATTR_CREATE) myflags |= O_EXCL;
+       if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
+       attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
+       if (attrfd >= 0) {
+               ret = solaris_write_xattr(attrfd, value, size);
+               close(attrfd);
+       }
+       return ret;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+int sys_fsetxattr (int filedes, const char *uname, const void *value, size_t size, int flags)
+{
+    const char *name = prefix(uname);
+
+#if defined(HAVE_FSETXATTR)
+#ifndef XATTR_ADD_OPT
+    return fsetxattr(filedes, name, value, size, flags);
+#else
+    int options = 0;
+    return fsetxattr(filedes, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_FSETEA)
+    return fsetea(filedes, name, value, size, flags);
+#elif defined(HAVE_EXTATTR_SET_FD)
+    char *s;
+    int retval = 0;
+    int attrnamespace = (strncmp(name, "system", 6) == 0) ? 
+        EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+    const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+    if (flags) {
+        /* Check attribute existence */
+        retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
+        if (retval < 0) {
+            /* REPLACE attribute, that doesn't exist */
+            if (flags & XATTR_REPLACE && errno == ENOATTR) {
+                errno = ENOATTR;
+                return -1;
+            }
+            /* Ignore other errors */
+        }
+        else {
+            log_error, logtype_default            /* CREATE attribute, that already exists */
+            if (flags & XATTR_CREATE) {
+                errno = EEXIST;
+                return -1;
+            }
+        }
+    }
+    retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
+    return (retval < 0) ? -1 : 0;
+#elif defined(HAVE_ATTR_SETF)
+    int myflags = 0;
+    char *attrname = strchr(name,'.') + 1;
+
+    if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
+    if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
+    if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
+
+    return attr_setf(filedes, attrname, (const char *)value, size, myflags);
+#elif defined(HAVE_ATTROPEN)
+    int ret = -1;
+    int myflags = O_RDWR | O_XATTR;
+    int attrfd;
+    if (flags & XATTR_CREATE) myflags |= O_EXCL;
+    if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
+    attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
+    if (attrfd >= 0) {
+        ret = solaris_write_xattr(attrfd, value, size);
+        close(attrfd);
+    }
+    return ret;
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int sys_lsetxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
+{
+       const char *name = prefix(uname);
+#if defined(HAVE_LSETXATTR)
+       return lsetxattr(path, name, value, size, flags);
+#elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
+       int options = XATTR_NOFOLLOW;
+       return setxattr(path, name, value, size, 0, options);
+#elif defined(LSETEA)
+       return lsetea(path, name, value, size, flags);
+#elif defined(HAVE_EXTATTR_SET_LINK)
+       int retval = 0;
+       if (flags) {
+               /* Check attribute existence */
+               retval = extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
+               if (retval < 0) {
+                       /* REPLACE attribute, that doesn't exist */
+                       if (flags & XATTR_REPLACE && errno == ENOATTR) {
+                               errno = ENOATTR;
+                               return -1;
+                       }
+                       /* Ignore other errors */
+               }
+               else {
+                       /* CREATE attribute, that already exists */
+                       if (flags & XATTR_CREATE) {
+                               errno = EEXIST;
+                               return -1;
+                       }
+               }
+       }
+
+       retval = extattr_set_link(path, EXTATTR_NAMESPACE_USER, uname, value, size);
+       return (retval < 0) ? -1 : 0;
+#elif defined(HAVE_ATTR_SET)
+       int myflags = ATTR_DONTFOLLOW;
+       char *attrname = strchr(name,'.') + 1;
+       
+       if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
+       if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
+       if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
+
+       return attr_set(path, attrname, (const char *)value, size, myflags);
+#elif defined(HAVE_ATTROPEN)
+       int ret = -1;
+       int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
+       int attrfd;
+       if (flags & XATTR_CREATE) myflags |= O_EXCL;
+       if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
+       attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
+       if (attrfd >= 0) {
+               ret = solaris_write_xattr(attrfd, value, size);
+               close(attrfd);
+       }
+       return ret;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
+/**************************************************************************
+ helper functions for Solaris' EA support
+****************************************************************************/
+#ifdef HAVE_ATTROPEN
+static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
+{
+       struct stat sbuf;
+
+       if (fstat(attrfd, &sbuf) == -1) {
+               return -1;
+       }
+
+       /* This is to return the current size of the named extended attribute */
+       if (size == 0) {
+               return sbuf.st_size;
+       }
+
+       /* check size and read xattr */
+       if (sbuf.st_size > size) {
+               return -1;
+       }
+
+       return read(attrfd, value, sbuf.st_size);
+}
+
+static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
+{
+       ssize_t len = 0;
+       DIR *dirp;
+       struct dirent *de;
+       int newfd = dup(attrdirfd);
+       /* CAUTION: The originating file descriptor should not be
+                   used again following the call to fdopendir().
+                   For that reason we dup() the file descriptor
+                   here to make things more clear. */
+       dirp = fdopendir(newfd);
+
+       while ((de = readdir(dirp))) {
+               size_t listlen;
+               if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ||
+                    !strcmp(de->d_name, "SUNWattr_ro") || !strcmp(de->d_name, "SUNWattr_rw")) 
+               {
+                       /* we don't want "." and ".." here: */
+                       LOG(log_maxdebug, logtype_default, "skipped EA %s\n",de->d_name);
+                       continue;
+               }
+
+               listlen = strlen(de->d_name);
+               if (size == 0) {
+                       /* return the current size of the list of extended attribute names*/
+                       len += listlen + 1;
+               } else {
+                       /* check size and copy entry + nul into list. */
+                       if ((len + listlen + 1) > size) {
+                               errno = ERANGE;
+                               len = -1;
+                               break;
+                       } else {
+                               strcpy(list + len, de->d_name);
+                               len += listlen;
+                               list[len] = '\0';
+                               ++len;
+                       }
+               }
+       }
+
+       if (closedir(dirp) == -1) {
+               LOG(log_debug, logtype_default, "closedir dirp failed: %s\n",strerror(errno));
+               return -1;
+       }
+       return len;
+}
+
+static int solaris_unlinkat(int attrdirfd, const char *name)
+{
+       if (unlinkat(attrdirfd, name, 0) == -1) {
+               return -1;
+       }
+       return 0;
+}
+
+static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
+{
+       int filedes = attropen(path, attrpath, oflag, mode);
+       if (filedes == -1) {
+               LOG(log_maxdebug, logtype_default, "attropen FAILED: path: %s, name: %s, errno: %s",
+            path, attrpath, strerror(errno));
+        errno = ENOATTR;
+       }
+       return filedes;
+}
+
+static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
+{
+       int filedes = openat(fildes, path, oflag, mode);
+       if (filedes == -1) {
+               LOG(log_maxdebug, logtype_default, "openat FAILED: fd: %d, path: %s, errno: %s",
+            filedes, path, strerror(errno));
+       }
+       return filedes;
+}
+
+static int solaris_write_xattr(int attrfd, const char *value, size_t size)
+{
+       if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
+               return 0;
+       } else {
+               LOG(log_maxdebug, logtype_default, "solaris_write_xattr FAILED!");
+               return -1;
+       }
+}
+
+#endif /*HAVE_ATTROPEN*/
+
diff --git a/libatalk/vfs/sys_ea.c b/libatalk/vfs/sys_ea.c
deleted file mode 100644 (file)
index 900eb07..0000000
+++ /dev/null
@@ -1,754 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   Samba system utilities
-   Copyright (C) Andrew Tridgell 1992-1998
-   Copyright (C) Jeremy Allison  1998-2005
-   Copyright (C) Timur Bakeyev        2005
-   Copyright (C) Bjoern Jacke    2006-2007
-   
-   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.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-   
-   sys_copyxattr modified from LGPL2.1 libattr copyright
-   Copyright (C) 2001-2002 Silicon Graphics, Inc.  All Rights Reserved.
-   Copyright (C) 2001 Andreas Gruenbacher.
-      
-   Samba 3.0.28, modified for netatalk.
-   $Id: sys_ea.c,v 1.6 2009-12-04 10:26:10 franklahm Exp $
-   
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <errno.h>
-
-#if HAVE_ATTR_XATTR_H
-#include <attr/xattr.h>
-#elif HAVE_SYS_XATTR_H
-#include <sys/xattr.h>
-#endif
-
-#ifdef HAVE_SYS_EA_H
-#include <sys/ea.h>
-#endif
-
-#ifdef HAVE_ATTROPEN
-
-#include <dirent.h>
-#endif
-
-#ifdef HAVE_SYS_EXTATTR_H
-#include <sys/extattr.h>
-#endif
-
-#include <atalk/adouble.h>
-#include <atalk/util.h>
-#include <atalk/logger.h>
-#include <atalk/ea.h>
-
-#ifndef ENOATTR
-#define ENOATTR ENODATA
-#endif
-
-/******** Solaris EA helper function prototypes ********/
-#ifdef HAVE_ATTROPEN
-#define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
-static int solaris_write_xattr(int attrfd, const char *value, size_t size);
-static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
-static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
-static int solaris_unlinkat(int attrdirfd, const char *name);
-static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
-static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
-#endif
-
-/**************************************************************************
- Wrappers for extented attribute calls. Based on the Linux package with
- support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
-****************************************************************************/
-static char attr_name[256 +5] = "user.";
-
-static const char *prefix(const char *uname)
-{
-#if defined(HAVE_ATTROPEN)
-       return uname;
-#else
-       strlcpy(attr_name +5, uname, 256);
-       return attr_name;
-#endif
-}
-
-ssize_t sys_getxattr (const char *path, const char *uname, void *value, size_t size)
-{
-       const char *name = prefix(uname);
-
-#if defined(HAVE_GETXATTR)
-#ifndef XATTR_ADD_OPT
-       return getxattr(path, name, value, size);
-#else
-       int options = 0;
-       return getxattr(path, name, value, size, 0, options);
-#endif
-#elif defined(HAVE_GETEA)
-       return getea(path, name, value, size);
-#elif defined(HAVE_EXTATTR_GET_FILE)
-       ssize_t retval;
-       /*
-        * The BSD implementation has a nasty habit of silently truncating
-        * the returned value to the size of the buffer, so we have to check
-        * that the buffer is large enough to fit the returned value.
-        */
-       if((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
-        if (size == 0)
-            /* size == 0 means only return size */
-            return retval;
-               if (retval > size) {
-                       errno = ERANGE;
-                       return -1;
-               }
-               if ((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
-                       return retval;
-       }
-
-       LOG(log_maxdebug, logtype_default, "sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno));
-       return -1;
-#elif defined(HAVE_ATTR_GET)
-       int retval, flags = 0;
-       int valuelength = (int)size;
-       char *attrname = strchr(name,'.') + 1;
-       
-       if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
-       retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
-
-       return retval ? retval : valuelength;
-#elif defined(HAVE_ATTROPEN)
-       ssize_t ret = -1;
-       int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
-       if (attrfd >= 0) {
-               ret = solaris_read_xattr(attrfd, value, size);
-               close(attrfd);
-       }
-       return ret;
-#else
-       errno = ENOSYS;
-       return -1;
-#endif
-}
-
-ssize_t sys_lgetxattr (const char *path, const char *uname, void *value, size_t size)
-{
-       const char *name = prefix(uname);
-
-#if defined(HAVE_LGETXATTR)
-       return lgetxattr(path, name, value, size);
-#elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
-       int options = XATTR_NOFOLLOW;
-       return getxattr(path, name, value, size, 0, options);
-#elif defined(HAVE_LGETEA)
-       return lgetea(path, name, value, size);
-#elif defined(HAVE_EXTATTR_GET_LINK)
-       ssize_t retval;
-       if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
-               if(retval > size) {
-                       errno = ERANGE;
-                       return -1;
-               }
-               if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
-                       return retval;
-       }
-       
-       LOG(log_maxdebug, logtype_default, "sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno));
-       return -1;
-#elif defined(HAVE_ATTR_GET)
-       int retval, flags = ATTR_DONTFOLLOW;
-       int valuelength = (int)size;
-       char *attrname = strchr(name,'.') + 1;
-       
-       if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
-       retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
-
-       return retval ? retval : valuelength;
-#elif defined(HAVE_ATTROPEN)
-       ssize_t ret = -1;
-       int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
-       if (attrfd >= 0) {
-               ret = solaris_read_xattr(attrfd, value, size);
-               close(attrfd);
-       }
-       return ret;
-#else
-       errno = ENOSYS;
-       return -1;
-#endif
-}
-
-#if defined(HAVE_EXTATTR_LIST_FILE)
-
-#define EXTATTR_PREFIX(s)      (s), (sizeof((s))-1)
-
-static struct {
-        int space;
-       const char *name;
-       size_t len;
-} 
-extattr[] = {
-       { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("") },
-        { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("") },
-};
-
-typedef union {
-       const char *path;
-       int filedes;
-} extattr_arg;
-
-static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
-{
-       ssize_t list_size;
-       int i, len;
-
-    switch(type) {
-#if defined(HAVE_EXTATTR_LIST_FILE)
-    case 0:
-        list_size = extattr_list_file(arg.path, EXTATTR_NAMESPACE_USER, list, size);
-        break;
-#endif
-#if defined(HAVE_EXTATTR_LIST_LINK)
-    case 1:
-        list_size = extattr_list_link(arg.path, EXTATTR_NAMESPACE_USER, list, size);
-        break;
-#endif
-#if defined(HAVE_EXTATTR_LIST_FD)
-    case 2:
-        list_size = extattr_list_fd(arg.filedes, EXTATTR_NAMESPACE_USER, list, size);
-        break;
-#endif
-    default:
-        errno = ENOSYS;
-        return -1;
-    }
-
-    /* Some error happend. Errno should be set by the previous call */
-    if(list_size < 0)
-        return -1;
-
-    /* No attributes */
-    if(list_size == 0)
-        return 0;
-
-    /* XXX: Call with an empty buffer may be used to calculate
-       necessary buffer size. Unfortunately, we can't say, how
-       many attributes were returned, so here is the potential
-       problem with the emulation.
-    */
-    if(list == NULL)
-        return list_size;
-
-    /* Buffer is too small to fit the results */
-    if(list_size > size) {
-        errno = ERANGE;
-        return -1;
-    }
-
-    /* Convert from pascal strings to C strings */
-    len = list[0];
-    memmove(list, list + 1, list_size);
-
-    for(i = len; i < list_size; ) {
-        LOG(log_maxdebug, logtype_afpd, "len: %d, i: %d", len, i);
-
-        len = list[i];
-        list[i] = '\0';
-        i += len + 1;
-    }
-
-       return list_size;
-}
-
-#endif
-
-#if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
-static char attr_buffer[ATTR_MAX_VALUELEN];
-
-static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
-{
-       int retval = 0, index;
-       attrlist_cursor_t *cursor = 0;
-       int total_size = 0;
-       attrlist_t * al = (attrlist_t *)attr_buffer;
-       attrlist_ent_t *ae;
-       size_t ent_size, left = size;
-       char *bp = list;
-
-       while (True) {
-           if (filedes)
-               retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
-           else
-               retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
-           if (retval) break;
-           for (index = 0; index < al->al_count; index++) {
-               ae = ATTR_ENTRY(attr_buffer, index);
-               ent_size = strlen(ae->a_name) + sizeof("user.");
-               if (left >= ent_size) {
-                   strncpy(bp, "user.", sizeof("user."));
-                   strncat(bp, ae->a_name, ent_size - sizeof("user."));
-                   bp += ent_size;
-                   left -= ent_size;
-               } else if (size) {
-                   errno = ERANGE;
-                   retval = -1;
-                   break;
-               }
-               total_size += ent_size;
-           }
-           if (al->al_more == 0) break;
-       }
-       if (retval == 0) {
-           flags |= ATTR_ROOT;
-           cursor = 0;
-           while (True) {
-               if (filedes)
-                   retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
-               else
-                   retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
-               if (retval) break;
-               for (index = 0; index < al->al_count; index++) {
-                   ae = ATTR_ENTRY(attr_buffer, index);
-                   ent_size = strlen(ae->a_name) + sizeof("system.");
-                   if (left >= ent_size) {
-                       strncpy(bp, "system.", sizeof("system."));
-                       strncat(bp, ae->a_name, ent_size - sizeof("system."));
-                       bp += ent_size;
-                       left -= ent_size;
-                   } else if (size) {
-                       errno = ERANGE;
-                       retval = -1;
-                       break;
-                   }
-                   total_size += ent_size;
-               }
-               if (al->al_more == 0) break;
-           }
-       }
-       return (ssize_t)(retval ? retval : total_size);
-}
-
-#endif
-
-#if defined(HAVE_LISTXATTR)
-static ssize_t remove_user(ssize_t ret, char *list, size_t size)
-{
-       size_t len;
-       char *ptr;
-       char *ptr1;
-       ssize_t ptrsize;
-       
-       if (ret <= 0 || size == 0)
-               return ret;
-       ptrsize = ret;
-       ptr = ptr1 = list;
-       while (ptrsize > 0) {
-               len = strlen(ptr1) +1;
-               ptrsize -= len;
-               if (strncmp(ptr1, "user.",5)) {
-                       ptr1 += len;
-                       continue;
-               }
-               memmove(ptr, ptr1 +5, len -5);
-               ptr += len -5;
-               ptr1 += len;
-       }
-       return ptr -list;
-}
-#endif
-
-ssize_t sys_listxattr (const char *path, char *list, size_t size)
-{
-#if defined(HAVE_LISTXATTR)
-       ssize_t ret;
-
-#ifndef XATTR_ADD_OPT
-       ret = listxattr(path, list, size);
-#else
-       int options = 0;
-       ret = listxattr(path, list, size, options);
-#endif
-       return remove_user(ret, list, size);
-
-#elif defined(HAVE_LISTEA)
-       return listea(path, list, size);
-#elif defined(HAVE_EXTATTR_LIST_FILE)
-       extattr_arg arg;
-       arg.path = path;
-       return bsd_attr_list(0, arg, list, size);
-#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
-       return irix_attr_list(path, 0, list, size, 0);
-#elif defined(HAVE_ATTROPEN)
-       ssize_t ret = -1;
-       int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
-       if (attrdirfd >= 0) {
-               ret = solaris_list_xattr(attrdirfd, list, size);
-               close(attrdirfd);
-       }
-       return ret;
-#else
-       errno = ENOSYS;
-       return -1;
-#endif
-}
-
-ssize_t sys_llistxattr (const char *path, char *list, size_t size)
-{
-#if defined(HAVE_LLISTXATTR)
-       ssize_t ret;
-
-       ret = llistxattr(path, list, size);
-       return remove_user(ret, list, size);
-#elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
-       ssize_t ret;
-       int options = XATTR_NOFOLLOW;
-
-       ret = listxattr(path, list, size, options);
-       return remove_user(ret, list, size);
-
-#elif defined(HAVE_LLISTEA)
-       return llistea(path, list, size);
-#elif defined(HAVE_EXTATTR_LIST_LINK)
-       extattr_arg arg;
-       arg.path = path;
-       return bsd_attr_list(1, arg, list, size);
-#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
-       return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
-#elif defined(HAVE_ATTROPEN)
-       ssize_t ret = -1;
-       int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
-       if (attrdirfd >= 0) {
-               ret = solaris_list_xattr(attrdirfd, list, size);
-               close(attrdirfd);
-       }
-       return ret;
-#else
-       errno = ENOSYS;
-       return -1;
-#endif
-}
-
-int sys_removexattr (const char *path, const char *uname)
-{
-       const char *name = prefix(uname);
-#if defined(HAVE_REMOVEXATTR)
-#ifndef XATTR_ADD_OPT
-       return removexattr(path, name);
-#else
-       int options = 0;
-       return removexattr(path, name, options);
-#endif
-#elif defined(HAVE_REMOVEEA)
-       return removeea(path, name);
-#elif defined(HAVE_EXTATTR_DELETE_FILE)
-       return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, uname);
-#elif defined(HAVE_ATTR_REMOVE)
-       int flags = 0;
-       char *attrname = strchr(name,'.') + 1;
-       
-       if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
-       return attr_remove(path, attrname, flags);
-#elif defined(HAVE_ATTROPEN)
-       int ret = -1;
-       int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
-       if (attrdirfd >= 0) {
-               ret = solaris_unlinkat(attrdirfd, name);
-               close(attrdirfd);
-       }
-       return ret;
-#else
-       errno = ENOSYS;
-       return -1;
-#endif
-}
-
-int sys_lremovexattr (const char *path, const char *uname)
-{
-       const char *name = prefix(uname);
-#if defined(HAVE_LREMOVEXATTR)
-       return lremovexattr(path, name);
-#elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
-       int options = XATTR_NOFOLLOW;
-       return removexattr(path, name, options);
-#elif defined(HAVE_LREMOVEEA)
-       return lremoveea(path, name);
-#elif defined(HAVE_EXTATTR_DELETE_LINK)
-       return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, uname);
-#elif defined(HAVE_ATTR_REMOVE)
-       int flags = ATTR_DONTFOLLOW;
-       char *attrname = strchr(name,'.') + 1;
-       
-       if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
-       return attr_remove(path, attrname, flags);
-#elif defined(HAVE_ATTROPEN)
-       int ret = -1;
-       int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
-       if (attrdirfd >= 0) {
-               ret = solaris_unlinkat(attrdirfd, name);
-               close(attrdirfd);
-       }
-       return ret;
-#else
-       errno = ENOSYS;
-       return -1;
-#endif
-}
-
-int sys_setxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
-{
-       const char *name = prefix(uname);
-#if defined(HAVE_SETXATTR)
-#ifndef XATTR_ADD_OPT
-       return setxattr(path, name, value, size, flags);
-#else
-       int options = 0;
-       return setxattr(path, name, value, size, 0, options);
-#endif
-#elif defined(HAVE_SETEA)
-       return setea(path, name, value, size, flags);
-#elif defined(HAVE_EXTATTR_SET_FILE)
-       int retval = 0;
-       if (flags) {
-               /* Check attribute existence */
-               retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
-               if (retval < 0) {
-                       /* REPLACE attribute, that doesn't exist */
-                       if (flags & XATTR_REPLACE && errno == ENOATTR) {
-                               errno = ENOATTR;
-                               return -1;
-                       }
-                       /* Ignore other errors */
-               }
-               else {
-                       /* CREATE attribute, that already exists */
-                       if (flags & XATTR_CREATE) {
-                               errno = EEXIST;
-                               return -1;
-                       }
-               }
-       }
-       retval = extattr_set_file(path, EXTATTR_NAMESPACE_USER, uname, value, size);
-       return (retval < 0) ? -1 : 0;
-#elif defined(HAVE_ATTR_SET)
-       int myflags = 0;
-       char *attrname = strchr(name,'.') + 1;
-       
-       if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
-       if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
-       if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
-
-       return attr_set(path, attrname, (const char *)value, size, myflags);
-#elif defined(HAVE_ATTROPEN)
-       int ret = -1;
-       int myflags = O_RDWR;
-       int attrfd;
-       if (flags & XATTR_CREATE) myflags |= O_EXCL;
-       if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
-       attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
-       if (attrfd >= 0) {
-               ret = solaris_write_xattr(attrfd, value, size);
-               close(attrfd);
-       }
-       return ret;
-#else
-       errno = ENOSYS;
-       return -1;
-#endif
-}
-
-int sys_lsetxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
-{
-       const char *name = prefix(uname);
-#if defined(HAVE_LSETXATTR)
-       return lsetxattr(path, name, value, size, flags);
-#elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
-       int options = XATTR_NOFOLLOW;
-       return setxattr(path, name, value, size, 0, options);
-#elif defined(LSETEA)
-       return lsetea(path, name, value, size, flags);
-#elif defined(HAVE_EXTATTR_SET_LINK)
-       int retval = 0;
-       if (flags) {
-               /* Check attribute existence */
-               retval = extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
-               if (retval < 0) {
-                       /* REPLACE attribute, that doesn't exist */
-                       if (flags & XATTR_REPLACE && errno == ENOATTR) {
-                               errno = ENOATTR;
-                               return -1;
-                       }
-                       /* Ignore other errors */
-               }
-               else {
-                       /* CREATE attribute, that already exists */
-                       if (flags & XATTR_CREATE) {
-                               errno = EEXIST;
-                               return -1;
-                       }
-               }
-       }
-
-       retval = extattr_set_link(path, EXTATTR_NAMESPACE_USER, uname, value, size);
-       return (retval < 0) ? -1 : 0;
-#elif defined(HAVE_ATTR_SET)
-       int myflags = ATTR_DONTFOLLOW;
-       char *attrname = strchr(name,'.') + 1;
-       
-       if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
-       if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
-       if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
-
-       return attr_set(path, attrname, (const char *)value, size, myflags);
-#elif defined(HAVE_ATTROPEN)
-       int ret = -1;
-       int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
-       int attrfd;
-       if (flags & XATTR_CREATE) myflags |= O_EXCL;
-       if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
-       attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
-       if (attrfd >= 0) {
-               ret = solaris_write_xattr(attrfd, value, size);
-               close(attrfd);
-       }
-       return ret;
-#else
-       errno = ENOSYS;
-       return -1;
-#endif
-}
-
-/**************************************************************************
- helper functions for Solaris' EA support
-****************************************************************************/
-#ifdef HAVE_ATTROPEN
-static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
-{
-       struct stat sbuf;
-
-       if (fstat(attrfd, &sbuf) == -1) {
-               return -1;
-       }
-
-       /* This is to return the current size of the named extended attribute */
-       if (size == 0) {
-               return sbuf.st_size;
-       }
-
-       /* check size and read xattr */
-       if (sbuf.st_size > size) {
-               return -1;
-       }
-
-       return read(attrfd, value, sbuf.st_size);
-}
-
-static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
-{
-       ssize_t len = 0;
-       DIR *dirp;
-       struct dirent *de;
-       int newfd = dup(attrdirfd);
-       /* CAUTION: The originating file descriptor should not be
-                   used again following the call to fdopendir().
-                   For that reason we dup() the file descriptor
-                   here to make things more clear. */
-       dirp = fdopendir(newfd);
-
-       while ((de = readdir(dirp))) {
-               size_t listlen;
-               if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ||
-                    !strcmp(de->d_name, "SUNWattr_ro") || !strcmp(de->d_name, "SUNWattr_rw")) 
-               {
-                       /* we don't want "." and ".." here: */
-                       LOG(log_maxdebug, logtype_default, "skipped EA %s\n",de->d_name);
-                       continue;
-               }
-
-               listlen = strlen(de->d_name);
-               if (size == 0) {
-                       /* return the current size of the list of extended attribute names*/
-                       len += listlen + 1;
-               } else {
-                       /* check size and copy entry + nul into list. */
-                       if ((len + listlen + 1) > size) {
-                               errno = ERANGE;
-                               len = -1;
-                               break;
-                       } else {
-                               strcpy(list + len, de->d_name);
-                               len += listlen;
-                               list[len] = '\0';
-                               ++len;
-                       }
-               }
-       }
-
-       if (closedir(dirp) == -1) {
-               LOG(log_debug, logtype_default, "closedir dirp failed: %s\n",strerror(errno));
-               return -1;
-       }
-       return len;
-}
-
-static int solaris_unlinkat(int attrdirfd, const char *name)
-{
-       if (unlinkat(attrdirfd, name, 0) == -1) {
-               return -1;
-       }
-       return 0;
-}
-
-static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
-{
-       int filedes = attropen(path, attrpath, oflag, mode);
-       if (filedes == -1) {
-               LOG(log_maxdebug, logtype_default, "attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno));
-        errno = ENOATTR;
-       }
-       return filedes;
-}
-
-static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
-{
-       int filedes = openat(fildes, path, oflag, mode);
-       if (filedes == -1) {
-               LOG(log_maxdebug, logtype_default, "openat FAILED: fd: %s, path: %s, errno: %s\n",filedes,path,strerror(errno));
-       }
-       return filedes;
-}
-
-static int solaris_write_xattr(int attrfd, const char *value, size_t size)
-{
-       if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
-               return 0;
-       } else {
-               LOG(log_maxdebug, logtype_default, "solaris_write_xattr FAILED!\n");
-               return -1;
-       }
-}
-
-#endif /*HAVE_ATTROPEN*/
-
index 3156afe33191433b0ac43cf7db77d1cb4d05e43e..57a4e0c2cb1bcd28237a3dce9735ce64138b4060 100644 (file)
@@ -493,368 +493,71 @@ EC_CLEANUP:
 }
 #endif
 
-/*********************************************************************************
- * sfm adouble format
- *********************************************************************************/
-static int ads_chown_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask _U_)
-{
-    struct perm   *owner  = data;
-    
-    if (chown( name , owner->uid, owner->gid ) < 0) {
-        return -1;
-    }
-    return 0;
-}
-
-static int RF_chown_ads(VFS_FUNC_ARGS_CHOWN)
-{
-    struct        stat st;
-    char          *ad_p;
-    struct perm   owner;
-    
-    owner.uid = uid;
-    owner.gid = gid;
-
-
-    ad_p = ad_dir(vol->ad_path(path, ADFLAGS_HF ));
-
-    if ( stat( ad_p, &st ) < 0 ) {
-       /* ignore */
-        return 0;
-    }
-    
-    if (chown( ad_p, uid, gid ) < 0) {
-       return -1;
-    }
-    return for_each_adouble("chown_ads", ad_p, ads_chown_loop, &owner, 1, vol->v_umask);
-}
-
-/* --------------------------------- */
-static int deletecurdir_ads1_loop(struct dirent *de _U_, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_)
-{
-    return netatalk_unlink(name);
-}
-
-static int ads_delete_rf(char *name)
-{
-    int err;
-
-    if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1, 0))) 
-        return err;
-    /* FIXME 
-     * it's a problem for a nfs mounted folder, there's .nfsxxx around
-     * for linux the following line solve it.
-     * but it could fail if rm .nfsxxx  create a new .nfsyyy :(
-    */
-    if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1, 0))) 
-        return err;
-    return netatalk_rmdir(-1, name);
-}
-
-static int deletecurdir_ads_loop(struct dirent *de, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_)
-{
-    struct stat st;
-    
-    /* bail if the file exists in the current directory.
-     * note: this will not fail with dangling symlinks */
-    
-    if (stat(de->d_name, &st) == 0) {
-        return AFPERR_DIRNEMPT;
-    }
-    return ads_delete_rf(name);
-}
-
-static int RF_deletecurdir_ads(VFS_FUNC_ARGS_DELETECURDIR)
-{
-    int err;
-
-    /* delete stray .AppleDouble files. this happens to get .Parent files as well. */
-    if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_ads_loop, NULL, 1, 0))) 
-        return err;
-
-    return netatalk_rmdir(-1, ".AppleDouble" );
-}
-
-/* ------------------- */
-struct set_mode {
-    mode_t mode;
-    struct stat *st;
-};
-
-static int ads_setfilmode_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask)
+/*************************************************************************
+ * EA adouble format 
+ ************************************************************************/
+static int validupath_ea(VFS_FUNC_ARGS_VALIDUPATH)
 {
-    struct set_mode *param = data;
-
-    return setfilmode(name, param->mode, param->st, v_umask);
-}
+    return 1;
+}             
 
-static int ads_setfilmode(const char * name, mode_t mode, struct stat *st, mode_t v_umask)
+/* ----------------- */
+static int RF_chown_ea(VFS_FUNC_ARGS_CHOWN)
 {
-    mode_t file_mode = ad_hf_mode(mode);
-    mode_t dir_mode = file_mode;
-    struct set_mode param;
-
-    if ((dir_mode & (S_IRUSR | S_IWUSR )))
-        dir_mode |= S_IXUSR;
-    if ((dir_mode & (S_IRGRP | S_IWGRP )))
-        dir_mode |= S_IXGRP;
-    if ((dir_mode & (S_IROTH | S_IWOTH )))
-        dir_mode |= S_IXOTH;   
-    
-       /* change folder */
-       dir_mode |= DIRBITS;
-    if (dir_rx_set(dir_mode)) {
-        if (chmod( name,  dir_mode ) < 0)
-            return -1;
-    }
-    param.st = st;
-    param.mode = file_mode;
-    if (for_each_adouble("setfilmode_ads", name, ads_setfilmode_loop, &param, 0, v_umask) < 0)
-        return -1;
-
-    if (!dir_rx_set(dir_mode)) {
-        if (chmod( name,  dir_mode ) < 0)
-            return -1;
-    }
-
     return 0;
 }
 
-static int RF_setfilmode_ads(VFS_FUNC_ARGS_SETFILEMODE)
+/* ---------------- */
+static int RF_renamedir_ea(VFS_FUNC_ARGS_RENAMEDIR)
 {
-    return ads_setfilmode(ad_dir(vol->ad_path(name, ADFLAGS_HF )), mode, st, vol->v_umask);
+    return 0;
 }
 
-/* ------------------- */
-static int RF_setdirunixmode_ads(VFS_FUNC_ARGS_SETDIRUNIXMODE)
+/* ---------------- */
+static int RF_deletecurdir_ea(VFS_FUNC_ARGS_DELETECURDIR)
 {
-    char *adouble = vol->ad_path(name, ADFLAGS_DIR );
-    char   ad_p[ MAXPATHLEN + 1];
-    int dropbox = vol->v_flags;
-
-    strlcpy(ad_p,ad_dir(adouble), MAXPATHLEN + 1);
-
-    if (dir_rx_set(mode)) {
-
-        /* .AppleDouble */
-        if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox, vol->v_umask) < 0) 
-            return -1;
-
-        /* .AppleDouble/.Parent */
-        if (stickydirmode(ad_p, DIRBITS | mode, dropbox, vol->v_umask) < 0) 
-            return -1;
-    }
-
-    if (ads_setfilmode(ad_dir(vol->ad_path(name, ADFLAGS_DIR)), mode, st, vol->v_umask) < 0)
-        return -1;
-
-    if (!dir_rx_set(mode)) {
-        if (stickydirmode(ad_p, DIRBITS | mode, dropbox, vol->v_umask) < 0) 
-            return  -1 ;
-        if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox, vol->v_umask) < 0) 
-            return -1;
-    }
     return 0;
 }
 
-/* ------------------- */
-struct dir_mode {
-    mode_t mode;
-    int    dropbox;
-};
-
-static int setdirmode_ads_loop(struct dirent *de _U_, char *name, void *data, int flag, mode_t v_umask)
+/* ---------------- */
+static int RF_setdirunixmode_ea(VFS_FUNC_ARGS_SETDIRUNIXMODE)
 {
-
-    struct dir_mode *param = data;
-    int    ret = 0; /* 0 ignore error, -1 */
-
-    if (dir_rx_set(param->mode)) {
-        if (stickydirmode(name, DIRBITS | param->mode, param->dropbox, v_umask) < 0) {
-            if (flag) {
-                return 0;
-            }
-            return ret;
-        }
-    }
-    if (ads_setfilmode(name, param->mode, NULL, v_umask) < 0)
-        return ret;
-
-    if (!dir_rx_set(param->mode)) {
-        if (stickydirmode(name, DIRBITS | param->mode, param->dropbox, v_umask) < 0) {
-            if (flag) {
-                return 0;
-            }
-            return ret;
-        }
-    }
     return 0;
 }
 
-static int RF_setdirmode_ads(VFS_FUNC_ARGS_SETDIRMODE)
+static int RF_setfilmode_ea(VFS_FUNC_ARGS_SETFILEMODE)
 {
-    char *adouble = vol->ad_path(name, ADFLAGS_DIR );
-    char   ad_p[ MAXPATHLEN + 1];
-    struct dir_mode param;
-
-    param.mode = mode;
-    param.dropbox = vol->v_flags;
-
-    strlcpy(ad_p,ad_dir(adouble), sizeof(ad_p));
-
-    if (dir_rx_set(mode)) {
-        /* .AppleDouble */
-        if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox, vol->v_umask) < 0) 
-            return -1;
-    }
-
-    if (for_each_adouble("setdirmode_ads", ad_dir(ad_p), setdirmode_ads_loop, &param, vol_noadouble(vol), vol->v_umask))
-        return -1;
-
-    if (!dir_rx_set(mode)) {
-        if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox, vol->v_umask) < 0 ) 
-            return -1;
-    }
     return 0;
 }
 
-/* ------------------- */
-static int setdirowner_ads1_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask _U_)
+/* ---------------- */
+static int RF_setdirmode_ea(VFS_FUNC_ARGS_SETDIRMODE)
 {
-    struct perm   *owner  = data;
-
-    if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
-         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
-                owner->uid, owner->gid, fullpathname(name), strerror(errno) );
-         /* return ( -1 ); Sometimes this is okay */
-    }
     return 0;
 }
 
-static int setdirowner_ads_loop(struct dirent *de _U_, char *name, void *data, int flag, mode_t v_umask _U_)
+/* ---------------- */
+static int RF_setdirowner_ea(VFS_FUNC_ARGS_SETDIROWNER)
 {
-    struct perm   *owner  = data;
-
-    if (for_each_adouble("setdirowner", name, setdirowner_ads1_loop, data, flag, 0) < 0)
-        return -1;
-
-    if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
-         LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
-                owner->uid, owner->gid, fullpathname(name), strerror(errno) );
-         /* return ( -1 ); Sometimes this is okay */
-    }
-    return 0;
+       return 0;
 }
 
-static int RF_setdirowner_ads(VFS_FUNC_ARGS_SETDIROWNER)
+static int RF_deletefile_ea(VFS_FUNC_ARGS_DELETEFILE)
 {
-    int           noadouble = vol_noadouble(vol);
-    char          adouble_p[ MAXPATHLEN + 1];
-    struct stat   st;
-    struct perm   owner;
-    
-    owner.uid = uid;
-    owner.gid = gid;
-
-    strlcpy(adouble_p, ad_dir(vol->ad_path(name, ADFLAGS_DIR )), sizeof(adouble_p));
-
-    if (for_each_adouble("setdirowner", ad_dir(adouble_p), setdirowner_ads_loop, &owner, noadouble, 0)) 
-        return -1;
-
-    /*
-     * We cheat: we know that chown doesn't do anything.
-     */
-    if ( stat( ".AppleDouble", &st ) < 0) {
-        if (errno == ENOENT && noadouble)
-            return 0;
-        LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
-        return -1;
-    }
-    if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) {
-        LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
-            uid, gid,fullpathname(".AppleDouble"), strerror(errno) );
-        /* return ( -1 ); Sometimes this is okay */
-    }
     return 0;
 }
-
-/* ------------------- */
-static int RF_deletefile_ads(VFS_FUNC_ARGS_DELETEFILE)
+static int RF_copyfile_ea(VFS_FUNC_ARGS_COPYFILE)
 {
-    int ret = 0;
-    int cwd = -1;
-    char *ad_p;
-
-    ad_p = ad_dir(vol->ad_path(file, ADFLAGS_HF ));
-
-    if (dirfd != -1) {
-        if (((cwd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-    }
-
-    ret = ads_delete_rf(ad_p);
-
-    if (dirfd != -1 && fchdir(cwd) != 0) {
-        LOG(log_error, logtype_afpd, "RF_deletefile_ads: cant chdir back. exit!");
-        exit(EXITERR_SYS);
-    }
-
-exit:
-    if (cwd != -1)
-        close(cwd);
-
-    return ret;
+    return 0;
 }
 
-/* --------------------------- */
-static int RF_renamefile_ads(VFS_FUNC_ARGS_RENAMEFILE)
+/* ---------------- */
+static int RF_renamefile_ea(VFS_FUNC_ARGS_RENAMEFILE)
 {
-    char  adsrc[ MAXPATHLEN + 1];
-    int   err = 0;
-
-    strcpy( adsrc, ad_dir(vol->ad_path(src, 0 )));
-    if (unix_rename(dirfd, adsrc, -1, ad_dir(vol->ad_path(dst, 0 ))) < 0) {
-        struct stat st;
-
-        err = errno;
-        if (errno == ENOENT) {
-               struct adouble    ad;
-
-            if (lstatat(dirfd, adsrc, &st)) /* source has no ressource fork, */
-                return 0;
-            
-            /* We are here  because :
-             * -there's no dest folder. 
-             * -there's no .AppleDouble in the dest folder.
-             * if we use the struct adouble passed in parameter it will not
-             * create .AppleDouble if the file is already opened, so we
-             * use a diff one, it's not a pb,ie it's not the same file, yet.
-             */
-            ad_init(&ad, vol->v_adouble, vol->v_ad_options); 
-            if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
-               ad_close(&ad, ADFLAGS_HF);
-
-               /* We must delete it */
-               RF_deletefile_ads(vol, -1, dst );
-               if (!unix_rename(dirfd, adsrc, -1, ad_dir(vol->ad_path(dst, 0 ))) ) 
-                   err = 0;
-                else 
-                   err = errno;
-            }
-            else { /* it's something else, bail out */
-                   err = errno;
-               }
-           }
-       }
-       if (err) {
-               errno = err;
-               return -1;
-       }
-       return 0;
+    return 0;
 }
 
+#if 0
 /*************************************************************************
  * osx adouble format 
  ************************************************************************/
@@ -915,6 +618,7 @@ static int RF_renamefile_osx(VFS_FUNC_ARGS_RENAMEFILE)
     }
     return 0;
 }
+#endif
 
 /********************************************************************************************
  * VFS chaining
@@ -1003,10 +707,10 @@ static struct vfs_ops vfs_master_funcs = {
 };
 
 /* 
- * Primary adouble modules: default, osx, sfm
+ * Primary adouble modules: v2, ea
  */
 
-static struct vfs_ops netatalk_adouble = {
+static struct vfs_ops netatalk_adouble_v2 = {
     /* vfs_validupath:    */ validupath_adouble,
     /* vfs_chown:         */ RF_chown_adouble,
     /* vfs_renamedir:     */ RF_renamedir_adouble,
@@ -1021,34 +725,18 @@ static struct vfs_ops netatalk_adouble = {
     NULL
 };
 
-static struct vfs_ops netatalk_adouble_osx = {
-    /* vfs_validupath:    */ validupath_osx,
-    /* vfs_chown:         */ RF_chown_adouble,
-    /* vfs_renamedir:     */ RF_renamedir_osx,
-    /* vfs_deletecurdir:  */ RF_deletecurdir_osx,
-    /* vfs_setfilmode:    */ RF_setfilmode_adouble,
-    /* vfs_setdirmode:    */ RF_setdirmode_osx,
-    /* vfs_setdirunixmode:*/ RF_setdirunixmode_osx,
-    /* vfs_setdirowner:   */ RF_setdirowner_osx,
-    /* vfs_deletefile:    */ RF_deletefile_adouble,
-    /* vfs_renamefile:    */ RF_renamefile_osx,
-    /* vfs_copyfile:      */ NULL,
-    NULL
-};
-
-/* samba sfm format. ad_path shouldn't be set her */
-static struct vfs_ops netatalk_adouble_sfm = {
-    /* vfs_validupath:    */ validupath_adouble,
-    /* vfs_chown:         */ RF_chown_ads,
-    /* vfs_renamedir:     */ RF_renamedir_adouble,
-    /* vfs_deletecurdir:  */ RF_deletecurdir_ads,
-    /* vfs_setfilmode:    */ RF_setfilmode_ads,
-    /* vfs_setdirmode:    */ RF_setdirmode_ads,
-    /* vfs_setdirunixmode:*/ RF_setdirunixmode_ads,
-    /* vfs_setdirowner:   */ RF_setdirowner_ads,
-    /* vfs_deletefile:    */ RF_deletefile_ads,
-    /* vfs_renamefile:    */ RF_renamefile_ads,
-    /* vfs_copyfile:      */ NULL,
+static struct vfs_ops netatalk_adouble_ea = {
+    /* vfs_validupath:    */ validupath_ea,
+    /* vfs_chown:         */ RF_chown_ea,
+    /* vfs_renamedir:     */ RF_renamedir_ea,
+    /* vfs_deletecurdir:  */ RF_deletecurdir_ea,
+    /* vfs_setfilmode:    */ RF_setfilmode_ea,
+    /* vfs_setdirmode:    */ RF_setdirmode_ea,
+    /* vfs_setdirunixmode:*/ RF_setdirunixmode_ea,
+    /* vfs_setdirowner:   */ RF_setdirowner_ea,
+    /* vfs_deletefile:    */ RF_deletefile_ea,
+    /* vfs_renamefile:    */ RF_renamefile_ea,
+    /* vfs_copyfile:      */ RF_copyfile_ea,
     NULL
 };
 
@@ -1150,17 +838,12 @@ void initvol_vfs(struct vol *vol)
     vol->vfs = &vfs_master_funcs;
 
     /* Default adouble stuff */
-    if (vol->v_adouble == AD_VERSION2_OSX) {
-        vol->vfs_modules[0] = &netatalk_adouble_osx;
-        vol->ad_path = ad_path_osx;
-    }
-    else if (vol->v_adouble == AD_VERSION1_SFM) {
-        vol->vfs_modules[0] = &netatalk_adouble_sfm;
-        vol->ad_path = ad_path_sfm;
-    }
-    else {
-        vol->vfs_modules[0] = &netatalk_adouble;
+    if (vol->v_adouble == AD_VERSION2) {
+        vol->vfs_modules[0] = &netatalk_adouble_v2;
         vol->ad_path = ad_path;
+    } else {
+        vol->vfs_modules[0] = &netatalk_adouble_ea;
+        vol->ad_path = ad_path_ea;
     }
 
     /* Extended Attributes */
index b3e6bdb54cab3b740bcb197136ba688cab1add3d..15371dba4abe3d969160d4ce9703e8351484ab86 100644 (file)
@@ -14,18 +14,13 @@ SUFFIXES= .tmpl .
 
 GENERATED_MANS = uniconv.1 asip-status.pl.1
 TEMPLATE_FILES = uniconv.1.tmpl asip-status.pl.1.tmpl
+
 NONGENERATED_MANS      =       ad.1 \
                                afppasswd.1 \
                                apple_dump.1 \
                                dbd.1 \
-                               hqx2bin.1 \
-                               macbinary.1 \
-                               megatron.1 \
-                               netatalk-config.1 \
-                               single2bin.1 \
-                               unbin.1 \
-                               unhex.1 \
-                               unsingle.1
+                               netatalk-config.1
+
 ATALK_MANS = aecho.1 \
                                getzones.1 \
                                nbp.1 \
index 9c9dceb70c0a1f003a5d9104563255f43fb66647..ddb2ab50bbd37181d57e3d11be57f4e48cc87967 100644 (file)
@@ -24,7 +24,7 @@
 #include <sys/types.h>
 #include <netinet/in.h> /* so that we can deal with sun's s_net #define */
 
-#ifdef MACOSX_SERVER
+#if defined(MACOSX_SERVER) && (!defined(NO_DDP))
 #include <netat/appletalk.h>
 #endif /* MACOSX_SERVER */