]> arthur.barton.de Git - netatalk.git/commitdiff
Merge master
authorFrank Lahm <franklahm@googlemail.com>
Sat, 8 Jan 2011 09:18:42 +0000 (10:18 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Sat, 8 Jan 2011 09:18:42 +0000 (10:18 +0100)
82 files changed:
VERSION
bin/Makefile.am
bin/ad/ad.h
bin/ad/ad_cp.c
bin/ad/ad_mv.c
bin/adv1tov2/.gitignore [deleted file]
bin/adv1tov2/Makefile.am [deleted file]
bin/adv1tov2/adv1tov2.c [deleted file]
bin/megatron/Makefile.am
configure.in
etc/afpd/afp_options.c
etc/afpd/desktop.c
etc/afpd/directory.c
etc/afpd/extattrs.c
etc/afpd/file.c
etc/afpd/fork.c
etc/afpd/ofork.c
etc/afpd/status.c
etc/afpd/uam.c
etc/afpd/unix.c
etc/afpd/volume.c
etc/cnid_dbd/cmd_dbd_scanvol.c
etc/cnid_dbd/comm.c
etc/cnid_dbd/dbd_search.c
etc/uams/uams_dhx_pam.c
include/atalk/adouble.h
include/atalk/cnid.h
include/atalk/cnid_dbd_private.h
include/atalk/dsi.h
include/atalk/ea.h
include/atalk/paths.h
include/atalk/util.h
include/atalk/uuid.h
include/atalk/volinfo.h
include/atalk/volume.h
libatalk/Makefile.am
libatalk/acl/cache.c
libatalk/acl/cache.h
libatalk/acl/unix.c
libatalk/acl/uuid.c
libatalk/adouble/Makefile.am
libatalk/adouble/ad_attr.c
libatalk/adouble/ad_date.c
libatalk/adouble/ad_flush.c
libatalk/adouble/ad_lock.c
libatalk/adouble/ad_lock.h [new file with mode: 0644]
libatalk/adouble/ad_mmap.c
libatalk/adouble/ad_open.c
libatalk/adouble/ad_private.h [deleted file]
libatalk/adouble/ad_read.c
libatalk/adouble/ad_sendfile.c
libatalk/adouble/ad_write.c
libatalk/cnid/cdb/cnid_cdb.h
libatalk/cnid/cdb/cnid_cdb_add.c
libatalk/cnid/cdb/cnid_cdb_get.c
libatalk/cnid/cdb/cnid_cdb_lookup.c
libatalk/cnid/cdb/cnid_cdb_open.c
libatalk/cnid/cdb/cnid_cdb_rebuild_add.c
libatalk/cnid/cdb/cnid_cdb_update.c
libatalk/cnid/dbd/cnid_dbd.c
libatalk/cnid/dbd/cnid_dbd.h
libatalk/cnid/last/cnid_last.c
libatalk/cnid/last/cnid_last.h
libatalk/cnid/tdb/cnid_tdb.h
libatalk/cnid/tdb/cnid_tdb_add.c
libatalk/cnid/tdb/cnid_tdb_get.c
libatalk/cnid/tdb/cnid_tdb_lookup.c
libatalk/cnid/tdb/cnid_tdb_open.c
libatalk/cnid/tdb/cnid_tdb_update.c
libatalk/compat/Makefile.am
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 423e7e84621bca9bc9a667bc7e1046352c0c8418..a857cca3d3e312b490138c61d02099639d36bf7f 100644 (file)
@@ -1,6 +1,6 @@
 # Makefile.am for bin/
 
-SUBDIRS = ad adv1tov2 afppasswd cnid megatron uniconv misc
+SUBDIRS = ad afppasswd cnid megatron uniconv misc
 
 if USE_APPLETALK
 SUBDIRS += aecho getzones nbp pap psorder
index 1b484e671d35cc1f650e6917f5e27d485d4fb50e..9f8fd4b5ae0dcb3692751d6d480cf71ca0fc17a0 100644 (file)
@@ -59,6 +59,7 @@ extern int ad_ls(int argc, char **argv);
 extern int ad_cp(int argc, char **argv);
 extern int ad_rm(int argc, char **argv);
 extern int ad_mv(int argc, char **argv);
+extern int ad_find(int argc, char **argv);
 
 /* ad_util.c */
 extern int openvol(const char *path, afpvol_t *vol);
index 97b30610080ac111b85ab9a5b4139ac1069fed85..0ee0f405947717ff9e801c53d02310d5e72746d7 100644 (file)
@@ -540,7 +540,7 @@ static int copy(const char *path,
                 break;
             }
             ad_init(&ad, dvolume.volinfo.v_adouble, dvolume.volinfo.v_ad_options);
-            if (ad_open_metadata(to.p_path, ADFLAGS_DIR, O_RDWR | O_CREAT, &ad) != 0) {
+            if (ad_open(&ad, to.p_path, ADFLAGS_HF | ADFLAGS_DIR, O_RDWR | O_CREAT, 0666) != 0) {
                 ERROR("Error opening adouble for: %s", to.p_path);
             }
             ad_setid( &ad, st.st_dev, st.st_ino, did, pdid, dvolume.db_stamp);
@@ -607,7 +607,7 @@ static int copy(const char *path,
                 break;
             }
             ad_init(&ad, dvolume.volinfo.v_adouble, dvolume.volinfo.v_ad_options);
-            if (ad_open_metadata(to.p_path, 0, O_RDWR | O_CREAT, &ad) != 0) {
+            if (ad_open(&ad, to.p_path, ADFLAGS_HF, O_RDWR | O_CREAT) != 0) {
                 ERROR("Error opening adouble for: %s", to.p_path);
             }
             ad_setid( &ad, st.st_dev, st.st_ino, cnid, did, dvolume.db_stamp);
index 342f22211d04e662ef9022601ef6df101a3bf764..0355364398e81183e566f040ee1a53e0d16d7265 100644 (file)
@@ -377,7 +377,7 @@ static int do_move(const char *from, const char *to)
 
         struct adouble ad;
         ad_init(&ad, dvolume.volinfo.v_adouble, dvolume.volinfo.v_ad_options);
-        if (ad_open_metadata(to, S_ISDIR(sb.st_mode) ? ADFLAGS_DIR : 0, O_RDWR, &ad) != 0) {
+        if (ad_open(&ad, to, S_ISDIR(sb.st_mode) ? (ADFLAGS_DIR | ADFLAGS_HF) : ADFLAGS_HF, O_RDWR) != 0) {
             SLOG("Error opening adouble for: %s", to);
             return 1;
         }
diff --git a/bin/adv1tov2/.gitignore b/bin/adv1tov2/.gitignore
deleted file mode 100644 (file)
index 4fada59..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Makefile
-Makefile.in
-adv1tov2
-.deps
-.libs
-.gitignore
-adv1tov2.o
diff --git a/bin/adv1tov2/Makefile.am b/bin/adv1tov2/Makefile.am
deleted file mode 100644 (file)
index 1bfc6ca..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# Makefile.am for bin/adv1tov2/
-
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
-
-bin_PROGRAMS = adv1tov2
-
-adv1tov2_SOURCES = adv1tov2.c
-adv1tov2_LDADD = $(top_builddir)/libatalk/libatalk.la
diff --git a/bin/adv1tov2/adv1tov2.c b/bin/adv1tov2/adv1tov2.c
deleted file mode 100644 (file)
index d4a66fb..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * $Id: adv1tov2.c,v 1.5 2009-10-14 01:38:28 didg Exp $
- * v1tov2: given a root directory, run down and convert all the
- * files/directories into appledouble v2.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include <atalk/adouble.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <dirent.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <errno.h>
-#include <string.h>
-
-#include <atalk/util.h>
-
-#if AD_VERSION == AD_VERSION2
-#if 0
-/* translate characters */
-static void xlate(char *name, int flags) {
-  static const char hexdig[] = "0123456789abcdef";
-  char upath[MAXPATHLEN + 1];
-  char *m, *u;
-  int doit = 0;
-
-  m = name;
-  u = upath;
-  while (*m != '\0') {
-    if (isascii(*m) && !isprint(*m)) {
-      doit = 1;
-      *u++ = ':';
-      *u++ = hexdig[(*m & 0xf0) >> 4];
-      *u++ = hexdig[*m & 0x0f];
-    } else
-      *u++ = *m;
-    m++;
-  }
-  
-  if (doit) {
-    *u = '\0';
-    rename(name, upath);
-    if ((flags & ADFLAGS_DIR) == 0)
-      rename(ad_path(name, flags), ad_path(upath, flags)); /* rename rfork */
-  }
-}
-#endif
-
-/* ----------------------------- */
-char *fullpathname(const char *name)
-{
-    static char wd[ MAXPATHLEN + 1];
-
-    if ( getcwd( wd , MAXPATHLEN) ) {
-        strlcat(wd, "/", MAXPATHLEN);
-        strlcat(wd, name, MAXPATHLEN);
-    }
-    else {
-        strlcpy(wd, name, MAXPATHLEN);
-    }
-    return wd;
-}
-
-#define MAXDESCEND 0xFFFF
-/* recursively descend subdirectories. 
- * oh the stack space we use up! */
-static void descend(DIR *dp)
-{
-  DIR *dpnew;
-  struct dirent *de;
-  struct stat st;
-  struct adouble ad;
-  int flags;
-  static int count = 0;
-
-  ad_init(&ad, AD_VERSION2, 0);
-  if (count++ > MAXDESCEND) {
-    fprintf(stderr, "FAILURE: too many subdirectories! possible infinite recursion.");
-    return;
-  }
-    
-  putc('(', stderr);
-  for (de = readdir(dp); de; de = readdir(dp)) {
-    if (de->d_name[0] == '.') 
-      continue;
-
-    if (stat(de->d_name, &st) < 0) {
-      fprintf(stderr, "FAILURE: can't stat %s\n", de->d_name);
-      continue;
-    }
-
-    /* go down subdirectory */
-    flags = ADFLAGS_HF;
-    if (S_ISDIR(st.st_mode) && (dpnew = opendir(de->d_name))) {
-      chdir(de->d_name);
-      descend(dpnew);
-      closedir(dpnew);
-      chdir("..");
-      flags |= ADFLAGS_DIR;
-    }
-
-    if (ad_open(de->d_name, flags, O_RDWR, 0, &ad) < 0) {
-      if (errno != ENOENT)
-          fprintf(stderr, "\nFAILURE: can't convert %s, %s\n", fullpathname(de->d_name), strerror(errno));
-      continue;
-    }
-    ad_close(&ad, ADFLAGS_HF);
-    fputc('.', stderr);
-  }
-  putc(')', stderr);
-}
-
-
-int main(int argc, char **argv)
-{
-  DIR           *dp;
-  struct adouble ad;
-  ad_init(&ad, AD_VERSION2, 0);
-  if (argc != 2) {
-    fprintf(stderr, "%s <directory>\n", *argv);
-    return -1;
-  }
-    
-  /* convert main directory */
-  if (ad_open(argv[1], ADFLAGS_HF | ADFLAGS_DIR, O_RDWR, 0, 
-             &ad) < 0) {
-    fprintf(stderr, "FAILURE: can't convert %s\n", argv[1]);
-    return -1;
-  }
-
-  ad_close(&ad, ADFLAGS_HF);
-  if ((dp = opendir(argv[1])) == NULL) {
-    fprintf(stderr, "%s: unable to open %s\n", *argv, argv[1]);
-    return -1;
-  }
-
-  chdir(argv[1]);
-  descend(dp);
-  closedir(dp);
-  chdir("..");
-
-  putc('\n', stderr);
-  return 0;
-}
-
-#else /* AD_VERSION == AD_VERSION2 */
-int main(int argc, char **argv)
-{
-  fprintf(stderr, "%s not built for v2 AppleDouble files.\n", *argv);
-  return -1;
-}
-#endif /* AD_VERSION == AD_VERSION2 */
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 407a594a769511d4aa39c9cbde24aba75b3c23a7..c966e464e8ccd2fbe0a716f619e3c76da9e6295d 100644 (file)
@@ -406,8 +406,10 @@ int afp_options_parseline(char *buf, struct afp_options *options)
 
     if ((c = getoption(buf, "-port")))
         options->port = strdup(c);
+#ifndef NO_DDP
     if ((c = getoption(buf, "-ddpaddr")))
         atalk_aton(c, &options->ddpaddr);
+#endif
     if ((c = getoption(buf, "-signature")) && (opt = strdup(c)))
         options->signatureopt = opt;
 
index 9f105e13e13c612757386f70c342626e28fe5e77..369b4aaa4ab7b8bc5d0ae11c71a7a12513726799 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: desktop.c,v 1.50.2.1 2010-02-01 10:56:08 franklahm Exp $
- *
  * See COPYRIGHT.
  *
  * bug:
@@ -694,7 +692,10 @@ static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
     } else
         adp = of->of_ad;
 
-    if (ad_open_metadata( upath , ( (isadir) ? ADFLAGS_DIR : 0), O_CREAT, adp) < 0 ) {
+    if (ad_open(adp, upath,
+                ADFLAGS_HF | ( (isadir) ? ADFLAGS_DIR : 0),
+                O_CREAT | O_RDWR,
+                0666) < 0 ) {
         return( AFPERR_ACCESS );
     }
 
@@ -711,7 +712,8 @@ static int ad_addcomment(struct vol *vol, struct path *path, char *ibuf)
         memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
         ad_flush( adp );
     }
-    ad_close_metadata( adp);
+    if (adp == &ad)
+        ad_close_metadata( adp);
     return( AFP_OK );
 }
 
@@ -844,7 +846,7 @@ static int ad_rmvcomment(struct vol *vol, struct path *path)
     } else
         adp = of->of_ad;
 
-    if ( ad_open_metadata( upath, (isadir) ? ADFLAGS_DIR : 0, 0, adp) < 0 ) {
+    if ( ad_open(adp, upath, ADFLAGS_HF | (isadir) ? ADFLAGS_DIR : 0, 0) < 0 ) {
         switch ( errno ) {
         case ENOENT :
             return( AFPERR_NOITEM );
index 55918eaeb8ed2ef6b8fa8dd0e064d01bc6c0ebbb..1bf8592276c1a970af5221418d9e5a072e22c4fb 100644 (file)
@@ -802,7 +802,7 @@ struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, i
 
     /* get_id needs adp for reading CNID from adouble file */
     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-    if ((ad_open_metadata(path->u_name, ADFLAGS_DIR, 0, &ad)) == 0) /* 1 */
+    if ((ad_open(&ad, path->u_name, ADFLAGS_HF | ADFLAGS_DIR)) == 0) /* 1 */
         adp = &ad;
 
     /* Get CNID */
@@ -1382,20 +1382,8 @@ int getdirparams(const struct vol *vol,
                    (1 << DIRPBIT_FINFO)))) {
 
         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-        if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
+        if ( !ad_metadata( upath, ADFLAGS_DIR, &ad) )
             isad = 1;
-            if (ad.ad_md->adf_flags & O_CREAT) {
-                /* We just created it */
-                ad_setname(&ad, s_path->m_name);
-                ad_setid( &ad,
-                          s_path->st.st_dev,
-                          s_path->st.st_ino,
-                          dir->d_did,
-                          dir->d_pdid,
-                          vol->v_stamp);
-                ad_flush( &ad);
-            }
-        }
     }
 
     pdid = dir->d_pdid;
@@ -1799,7 +1787,7 @@ int setdirparams(struct vol *vol, struct path *path, u_int16_t d_bitmap, char *b
     }
     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
 
-    if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
+    if (ad_open(&ad, upath, ADFLAGS_HF | ADFLAGS_DIR, O_CREAT, 0777) != 0) {
         /*
          * Check to see what we're trying to set.  If it's anything
          * but ACCESS, UID, or GID, give an error.  If it's any of those
@@ -2152,7 +2140,7 @@ int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_
     }
 
     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-    if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0)  {
+    if (ad_open(&ad, ".", ADFLAGS_HF | ADFLAGS_DIR, O_CREAT, 0777) < 0)  {
         if (vol_noadouble(vol))
             goto createdir_done;
         return( AFPERR_ACCESS );
@@ -2218,7 +2206,7 @@ int renamedir(const struct vol *vol,
 
     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
 
-    if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
+    if (ad_open(&ad, dst, ADFLAGS_HF | ADFLAGS_DIR) == 0) {
         ad_setname(&ad, newname);
         ad_flush( &ad);
         ad_close_metadata( &ad);
index 649cc6a30f3044b96533412751f850acee8a10be..060011f1681badeeb52fab32e32ebfd472b418a8 100644 (file)
@@ -1,5 +1,4 @@
 /*
-  $Id: extattrs.c,v 1.29 2010-01-05 12:06:33 franklahm Exp $
   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
@@ -139,7 +138,6 @@ int afp_listextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
             return( AFPERR_NOOBJ );
         }
 
-        adp = of_ad(vol, s_path, &ad);
         uname = s_path->u_name;
         /*
           We have to check the FinderInfo for the file, because if they aren't all 0
@@ -151,10 +149,11 @@ int afp_listextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
         if (S_ISDIR(st->st_mode))
             adflags = ADFLAGS_DIR;
 
-        if ( ad_metadata( uname, adflags, adp) < 0 ) {
+        adp = &ad;
+        ad_init(adp, vol->v_adouble, vol->v_ad_options);
+        if (ad_metadata(uname, adflags, adp) != 0 ) {
             switch (errno) {
             case ENOENT:
-                adp = NULL;
                 break;
             case EACCES:
                 LOG(log_error, logtype_afpd, "afp_listextattr(%s): %s: check resource fork permission?",
@@ -164,16 +163,9 @@ int afp_listextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
                 LOG(log_error, logtype_afpd, "afp_listextattr(%s): error getting metadata: %s", uname, strerror(errno));
                 return AFPERR_MISC;
             }
-        }
-
-        if (adp) {
+        } else {
             FinderInfo = ad_entry(adp, ADEID_FINDERI);
 
-#ifdef DEBUG
-            LOG(log_maxdebug, logtype_afpd, "afp_listextattr(%s): FinderInfo:", uname);
-            hexdump( FinderInfo, 32);
-#endif
-
             if ((adflags & ADFLAGS_DIR)) {
                 /* set default view */
                 uint16 = htons(FINDERINFO_CLOSEDVIEW);
@@ -214,7 +206,7 @@ int afp_listextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
         default:
             buf_valid = 1;
         }
-    }
+    } /* if ((maxreply == 0) || (buf_valid == 0)) */
 
     /* Start building reply packet */
     bitmap = htons(bitmap);
@@ -240,8 +232,9 @@ int afp_listextattr(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf,
 exit:
     if (ret != AFP_OK)
         buf_valid = 0;
+
     if (adp)
-        ad_close_metadata( adp);
+        ad_close_metadata(adp);
 
     return ret;
 }
index d3bf5600b36e1f68c91a15d3b1fadfe2eaa73f71..dc01ee60ed0c1a7b626c87f551bce40c9fe08903 100644 (file)
@@ -623,7 +623,7 @@ int getfilparams(struct vol *vol,
         adp = of_ad(vol, path, &ad);
         upath = path->u_name;
 
-        if ( ad_metadata( upath, flags|ADFLAGS_CREATE, adp) < 0 ) {
+        if ( ad_metadata( upath, flags, adp) < 0 ) {
             switch (errno) {
             case EACCES:
                 LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
@@ -640,7 +640,7 @@ int getfilparams(struct vol *vol,
         }
     }
     rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
-    if ( adp ) {
+    if ( adp == &ad ) {
         ad_close_metadata( adp);
     }
 
@@ -650,7 +650,7 @@ int getfilparams(struct vol *vol,
 /* ----------------------------- */
 int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
-    struct adouble     ad, *adp;
+    struct adouble     ad;
     struct vol         *vol;
     struct dir         *dir;
     struct ofork        *of = NULL;
@@ -666,9 +666,8 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
     memcpy(&vid, ibuf, sizeof( vid ));
     ibuf += sizeof( vid );
 
-    if (NULL == ( vol = getvolbyvid( vid )) ) {
+    if (NULL == ( vol = getvolbyvid( vid )) )
         return( AFPERR_PARAM );
-    }
 
     if (vol->v_flags & AFPVOL_RO)
         return AFPERR_VLOCK;
@@ -676,44 +675,35 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_,
     memcpy(&did, ibuf, sizeof( did));
     ibuf += sizeof( did );
 
-    if (NULL == ( dir = dirlookup( vol, did )) ) {
+    if (NULL == ( dir = dirlookup( vol, did )) )
         return afp_errno;
-    }
 
-    if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
+    if (NULL == ( s_path = cname( vol, dir, &ibuf )) )
         return get_afp_errno(AFPERR_PARAM);
-    }
 
-    if ( *s_path->m_name == '\0' ) {
+    if ( *s_path->m_name == '\0' )
         return( AFPERR_BADTYPE );
-    }
 
     upath = s_path->u_name;
+    ad_init(&ad, vol->v_adouble, vol->v_ad_options);
     
     /* if upath is deleted we already in trouble anyway */
     if ((of = of_findname(s_path))) {
-        adp = of->of_ad;
-    } else {
-        ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-        adp = &ad;
-    }
-    if ( creatf) {
-        /* on a hard create, fail if file exists and is open */
-        if (of)
+        if (creatf)
             return AFPERR_BUSY;
+        else
+            return AFPERR_EXIST;
+    }
+
+    if ( creatf)
         openf = O_RDWR|O_CREAT|O_TRUNC;
-    } else {
+    else
        /* on a soft create, if the file is open then ad_open won't fail
-          because open syscall is not called
-       */
-       if (of) {
-               return AFPERR_EXIST;
-       }
+          because open syscall is not called */
         openf = O_RDWR|O_CREAT|O_EXCL;
-    }
 
-    if ( ad_open( upath, ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
-                  openf, 0666, adp) < 0 ) {
+    if ( ad_open(&ad, upath, ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF,
+                 openf, 0666, openf, 0666) < 0 ) {
         switch ( errno ) {
         case EROFS:
             return AFPERR_VLOCK;
@@ -730,24 +720,24 @@ 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( &ad ) == -1 ) { /* Hard META / HF */
          /* on noadouble volumes, just creating the data fork is ok */
          if (vol_noadouble(vol)) {
-             ad_close( adp, ADFLAGS_DF );
+             ad_close( &ad, ADFLAGS_DF );
              goto createfile_done;
          }
          /* FIXME with hard create on an existing file, we already
           * corrupted the data file.
           */
          netatalk_unlink( upath );
-         ad_close( adp, ADFLAGS_DF );
+         ad_close( &ad, ADFLAGS_DF );
          return AFPERR_ACCESS;
     }
 
     path = s_path->m_name;
-    ad_setname(adp, path);
-    ad_flush( adp);
-    ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
+    ad_setname(&ad, path);
+    ad_flush(&ad);
+    ad_close(&ad, ADFLAGS_DF|ADFLAGS_HF );
 
 createfile_done:
     curdir->offcnt++;
@@ -972,7 +962,7 @@ int setfilparams(struct vol *vol,
 
     /* second try with adouble open 
     */
-    if ( ad_open_metadata( upath, 0, O_CREAT, adp) < 0) {
+    if ( ad_open(adp, upath, ADFLAGS_HF, O_RDWR | O_CREAT, 0666) < 0) {
         LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
         /*
          * For some things, we don't need an adouble header:
@@ -1065,8 +1055,8 @@ setfilparam_done:
 
     if (isad) {
         ad_flush( adp);
-        ad_close_metadata( adp);
-
+        if (adp == &ad)
+            ad_close_metadata( adp);
     }
 
     if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
@@ -1151,7 +1141,7 @@ int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *n
 
     /* don't care if we can't open the newly renamed ressource fork
      */
-    if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
+    if (ad_open(adp, dst, ADFLAGS_HF, O_RDWR) == 0) {
         ad_setname(adp, newname);
         ad_flush( adp );
         ad_close( adp, ADFLAGS_HF );
@@ -1279,7 +1269,7 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si
 
     adp = of_ad(s_vol, s_path, &ad);
 
-    if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
+    if (ad_open(adp, s_path->u_name, ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, O_RDONLY) < 0) {
         return AFPERR_DENYCONF;
     }
     denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 || 
@@ -1355,7 +1345,8 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si
     setvoltime(obj, d_vol );
 
 copy_exit:
-    ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
+    if (adp == &ad)
+        ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
     return( retvalue );
 }
 
@@ -1490,7 +1481,7 @@ int copyfile(const struct vol *s_vol,
         adflags |= ADFLAGS_HF;
     }
 
-    if (ad_openat(sfd, src, adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
+    if (ad_openat(adp, sfd, src, adflags | ADFLAGS_NOHF, O_RDONLY) < 0) {
         ret_err = errno;
         goto done;
     }
@@ -1508,7 +1499,7 @@ int copyfile(const struct vol *s_vol,
     }
 
     ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
-    if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
+    if (ad_open(&add, dst, adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, O_RDWR|O_CREAT|O_EXCL, st.st_mode) < 0) {
         ret_err = errno;
         ad_close( adp, adflags );
         if (EEXIST != ret_err) {
@@ -1634,7 +1625,7 @@ int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib)
  
     /* try to open both forks at once */
     adflags = ADFLAGS_DF;
-    if ( ad_openat(dirfd, file, adflags |ADFLAGS_HF|ADFLAGS_NOHF, O_RDONLY, 0, &ad ) < 0 ) {
+    if ( ad_openat(&ad, dirfd, file, adflags |ADFLAGS_HF|ADFLAGS_NOHF, O_RDONLY) < 0 ) {
         switch (errno) {
         case ENOENT:
             err = AFPERR_NOOBJ;
@@ -1777,32 +1768,12 @@ static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data)
     cnid_t        did  = param->did;
     cnid_t       aint;
     
-    if ( lstat(de->d_name, &path.st)<0 )
+    if ( lstat(de->d_name, &path.st) < 0 )
         return 0;
     
     /* update or add to cnid */
     aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
 
-#if AD_VERSION > AD_VERSION1
-    if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
-        struct adouble  ad, *adp;
-
-        path.st_errno = 0;
-        path.st_valid = 1;
-        path.u_name = de->d_name;
-            
-        adp = of_ad(vol, &path, &ad);
-            
-        if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
-            return 0;
-        }
-        if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
-            ad_flush(adp);
-        }
-        ad_close_metadata(adp);
-    }
-#endif /* AD_VERSION > AD_VERSION1 */
-
     return 0;
 }
 
@@ -2064,7 +2035,7 @@ static struct adouble *find_adouble(struct path *path, struct ofork **of, struct
         adp = (*of)->of_ad;
     }
     else {
-        ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
+        ret = ad_open(adp, path->u_name, ADFLAGS_HF, O_RDONLY);
         /* META and HF */
         if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
             /* from AFP spec.
index f4d0d04cbee4c9f4ee93952c35469010e8f0b688..1ad11e4ef6a56a52cdbca89bd9076a89054ba227 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $Id: fork.c,v 1.73 2010-03-30 12:55:26 franklahm Exp $
- *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
+ * Copyright (c) 2010      Frank Lahm
+ *
  * All Rights Reserved.  See COPYRIGHT.
  */
 
 #endif /* HAVE_CONFIG_H */
 
 #include <stdio.h>
-
 #include <string.h>
 #include <errno.h>
-
-#include <atalk/adouble.h>
-#include <atalk/logger.h>
-
 #include <sys/param.h>
 #include <sys/socket.h>
+#include <inttypes.h>
 
 #include <netatalk/at.h>
-
 #include <atalk/dsi.h>
 #include <atalk/atp.h>
 #include <atalk/asp.h>
 #include <atalk/afp.h>
-
+#include <atalk/adouble.h>
+#include <atalk/logger.h>
 #include <atalk/util.h>
 #include <atalk/cnid.h>
+#include <atalk/bstradd.h>
 
 #include "fork.h"
 #include "file.h"
@@ -50,19 +47,19 @@ struct ofork *writtenfork;
 static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
 {
     struct path         path;
-    struct stat                *st;
+    struct stat     *st;
+
+    struct adouble  *adp;
+    struct dir      *dir;
+    struct vol      *vol;
 
-    struct adouble     *adp;
-    struct dir         *dir;
-    struct vol         *vol;
-    
 
     /* can only get the length of the opened fork */
-    if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN))) 
-                  && (ofork->of_flags & AFPFORK_RSRC)) 
-        ||
-          ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN))) 
-                  && (ofork->of_flags & AFPFORK_DATA))) {
+    if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
+           && (ofork->of_flags & AFPFORK_RSRC))
+         ||
+         ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
+           && (ofork->of_flags & AFPFORK_DATA))) {
         return( AFPERR_BITMAP );
     }
 
@@ -81,8 +78,8 @@ static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_
     path.m_name = of_name(ofork);
     path.id = 0;
     st = &path.st;
-    if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) | 
-                    (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) | 
+    if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
+                    (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
                     (1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
         if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
             /* 0 is for symlink */
@@ -116,7 +113,7 @@ static off_t get_off_t(char **ibuf, int is64)
         ret = ntohl(temp)| (ret << 32);
     }
     else {
-       ret = (int)ret; /* sign extend */
+        ret = (int)ret; /* sign extend */
     }
     return ret;
 }
@@ -142,38 +139,38 @@ static int set_off_t(off_t offset, char *rbuf, int is64)
     return ret;
 }
 
-/* ------------------------ 
-*/
+/* ------------------------
+ */
 static int is_neg(int is64, off_t val)
 {
     if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
-       return 1;
+        return 1;
     return 0;
 }
 
-static int sum_neg(int is64, off_t offset, off_t reqcount) 
+static int sum_neg(int is64, off_t offset, off_t reqcount)
 {
-    if (is_neg(is64, offset +reqcount) ) 
-       return 1;
+    if (is_neg(is64, offset +reqcount) )
+        return 1;
     return 0;
 }
 
 /* -------------------------
-*/
+ */
 static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
 {
     return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
 }
 
 /* -------------------------
-*/
+ */
 int getforkmode(struct adouble *adp, int eid, int what)
 {
     return ad_testlock(adp, eid,  what);
 }
 
 /* -------------------------
-*/
+ */
 static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
 {
     int ret;
@@ -199,9 +196,9 @@ static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
         if ((access & OPENACC_DRD) && readset) {
             errno = EACCES;
             return -1;
-        }   
+        }
         /* boolean logic is not enough, because getforkmode is not always telling the
-         * true 
+         * true
          */
         if ((access & OPENACC_RD)) {
             ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
@@ -228,7 +225,7 @@ static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
         if ((access & OPENACC_DWR) && writeset) {
             errno = EACCES;
             return -1;
-        }   
+        }
         if ((access & OPENACC_WR)) {
             ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
             if (ret)
@@ -249,19 +246,19 @@ static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
 /* ----------------------- */
 int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
 {
-    struct vol         *vol;
-    struct dir         *dir;
-    struct ofork       *ofork, *opened;
-    struct adouble      *adsame = NULL;
-    size_t             buflen;
-    int                        ret, adflags, eid;
-    u_int32_t           did;
-    u_int16_t          vid, bitmap, access, ofrefnum;
-    char               fork, *path, *upath;
-    struct stat         *st;
-    u_int16_t           bshort;
-    struct path         *s_path;
-    
+    struct vol      *vol;
+    struct dir      *dir;
+    struct ofork    *ofork, *opened;
+    struct adouble  *adsame = NULL;
+    size_t          buflen;
+    int             ret, adflags, eid;
+    uint32_t        did;
+    uint16_t        vid, bitmap, access, ofrefnum;
+    char            fork, *path, *upath;
+    struct stat     *st;
+    uint16_t        bshort;
+    struct path     *s_path;
+
     ibuf++;
     fork = *ibuf++;
     memcpy(&vid, ibuf, sizeof( vid ));
@@ -276,7 +273,7 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
     ibuf += sizeof( int );
 
     if (NULL == ( dir = dirlookup( vol, did ))) {
-       return afp_errno;    
+        return afp_errno;
     }
 
     memcpy(&bitmap, ibuf, sizeof( bitmap ));
@@ -291,14 +288,19 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
     }
 
     if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
-       return get_afp_errno(AFPERR_PARAM);    
+        return get_afp_errno(AFPERR_PARAM);
     }
 
     if (*s_path->m_name == '\0') {
-       /* it's a dir ! */
-       return  AFPERR_BADTYPE;
+        /* it's a dir ! */
+        return  AFPERR_BADTYPE;
     }
 
+    LOG(log_debug, logtype_afpd,
+        "afp_openfork(\"%s\", fork: %s)",
+        abspath(s_path->u_name),
+        (fork & OPENFORK_DATA) ? "d" : "r");
+
     /* stat() data fork st is set because it's not a dir */
     switch ( s_path->st_errno ) {
     case 0:
@@ -317,8 +319,7 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
         if (check_access(upath, access ) < 0) {
             return AFPERR_ACCESS;
         }
-    }
-    else {
+    } else {
         if (file_access(s_path, access ) < 0) {
             return AFPERR_ACCESS;
         }
@@ -328,9 +329,9 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
     /* XXX: this probably isn't the best way to do this. the already
        open bits should really be set if the fork is opened by any
        program, not just this one. however, that's problematic to do
-       if we can't write lock files somewhere. opened is also passed to 
+       if we can't write lock files somewhere. opened is also passed to
        ad_open so that we can keep file locks together.
-       FIXME: add the fork we are opening? 
+       FIXME: add the fork we are opening?
     */
     if ((opened = of_findname(s_path))) {
         adsame = opened->of_ad;
@@ -338,10 +339,10 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
 
     if ( fork == OPENFORK_DATA ) {
         eid = ADEID_DFORK;
-        adflags = ADFLAGS_DF|ADFLAGS_HF;
+        adflags = ADFLAGS_DF | ADFLAGS_HF;
     } else {
         eid = ADEID_RFORK;
-        adflags = ADFLAGS_HF;
+        adflags = ADFLAGS_RF | ADFLAGS_HF;
     }
 
     path = s_path->m_name;
@@ -353,7 +354,7 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
     ret = AFPERR_NOOBJ;
     if (access & OPENACC_WR) {
         /* try opening in read-write mode */
-        if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
+        if (ad_open(ofork->of_ad, upath, adflags, O_RDWR, O_RDWR) < 0) {
             switch ( errno ) {
             case EROFS:
                 ret = AFPERR_VLOCK;
@@ -363,15 +364,14 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
             case ENOENT:
                 if (fork == OPENFORK_DATA) {
                     /* try to open only the data fork */
-                    if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
+                    if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDWR) < 0) {
                         goto openfork_err;
                     }
                     adflags = ADFLAGS_DF;
-                }
-                else {
+                } else {
                     /* here's the deal. we only try to create the resource
-                    * fork if the user wants to open it for write acess. */
-                    if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
+                     * fork if the user wants to open it for write acess. */
+                    if (ad_open(ofork->of_ad, upath, adflags, O_RDWR | O_CREAT, 0666, O_RDWR | O_CREAT, 0666) < 0)
                         goto openfork_err;
                     ofork->of_flags |= AFPFORK_OPEN;
                 }
@@ -399,7 +399,7 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
     } else {
         /* try opening in read-only mode */
         ret = AFPERR_NOOBJ;
-        if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
+        if (ad_open(ofork->of_ad, upath, adflags, O_RDONLY, O_RDONLY) < 0) {
             switch ( errno ) {
             case EROFS:
                 ret = AFPERR_VLOCK;
@@ -409,19 +409,19 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
             case ENOENT:
                 /* see if client asked for a read only data fork */
                 if (fork == OPENFORK_DATA) {
-                    if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
+                    if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDONLY) < 0) {
                         goto openfork_err;
                     }
                     adflags = ADFLAGS_DF;
                 }
-                /* else we don't set AFPFORK_OPEN because there's no ressource fork file 
+                /* else we don't set AFPFORK_OPEN because there's no ressource fork file
                  * We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
                  * then create in open read-write.
                  * FIXME , it doesn't play well with byte locking example:
                  * ressource fork open read only
                  * locking set on it (no effect, there's no file!)
                  * ressource fork open read write now
-                */
+                 */
                 break;
             case EMFILE :
             case ENFILE :
@@ -433,8 +433,8 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
                 goto openfork_err;
                 break;
             default:
-                LOG(log_error, logtype_afpd, "afp_openfork('%s/%s'): ad_open: errno: %i (%s)",
-                    getcwdpath, s_path->m_name, errno, strerror(errno) );
+                LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
+                    abspath(s_path->m_name), strerror(errno) );
                 goto openfork_err;
                 break;
             }
@@ -463,7 +463,7 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si
     rbuf += sizeof( u_int16_t );
 
     /* check  WriteInhibit bit if we have a ressource fork
-     * the test is done here, after some Mac trafic capture 
+     * the test is done here, after some Mac trafic capture
      */
     if (ad_meta_fileno(ofork->of_ad) != -1) {   /* META */
         ad_getattr(ofork->of_ad, &bshort);
@@ -522,14 +522,14 @@ openfork_err:
 
 int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
 {
-    struct ofork       *ofork;
-    off_t              size;
-    u_int16_t          ofrefnum, bitmap;
+    struct ofork    *ofork;
+    off_t       size;
+    u_int16_t       ofrefnum, bitmap;
     int                 err;
     int                 is64;
     int                 eid;
-    off_t              st_size;
-    
+    off_t       st_size;
+
     ibuf += 2;
 
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
@@ -558,26 +558,26 @@ int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U
     } else
         return AFPERR_PARAM;
 
-    if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) )) 
-                  && eid == ADEID_RFORK 
-         ) ||
-         ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) )) 
-                  && eid == ADEID_DFORK)) {
+    if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
+           && eid == ADEID_RFORK
+             ) ||
+         ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
+           && eid == ADEID_DFORK)) {
         return AFPERR_BITMAP;
     }
-    
+
     is64 = 0;
     if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
         if (afp_version >= 30) {
             is64 = 4;
         }
-        else 
-           return AFPERR_BITMAP;
+        else
+            return AFPERR_BITMAP;
     }
 
     if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
         return AFPERR_PARAM ;
-    
+
     size = get_off_t(&ibuf, is64);
 
     if (size < 0)
@@ -585,29 +585,29 @@ int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U
 
 
     if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
-       st_size = ad_size(ofork->of_ad, eid);
-       err = -2;
-       if (st_size > size && 
-             ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) 
+        st_size = ad_size(ofork->of_ad, eid);
+        err = -2;
+        if (st_size > size &&
+            ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
             goto afp_setfork_err;
 
         err = ad_dtruncate( ofork->of_ad, size );
         if (st_size > size)
-           ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);  
+            ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
         if (err < 0)
             goto afp_setfork_err;
     } else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
         ad_refresh( ofork->of_ad );
 
-       st_size = ad_size(ofork->of_ad, eid);
-       err = -2;
-       if (st_size > size && 
-              ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
+        st_size = ad_size(ofork->of_ad, eid);
+        err = -2;
+        if (st_size > size &&
+            ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
             goto afp_setfork_err;
-       }
+        }
         err = ad_rtruncate(ofork->of_ad, size);
         if (st_size > size)
-           ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);  
+            ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
         if (err < 0)
             goto afp_setfork_err;
 
@@ -650,7 +650,7 @@ afp_setfork_err:
  * read and write. that's most easily handled by always doing an
  * appropriate check before each ad_read/ad_write. other things
  * that can change files like truncate are handled internally to those
- * functions. 
+ * functions.
  */
 #define ENDBIT(a)  ((a) & 0x80)
 #define UNLOCKBIT(a) ((a) & 0x01)
@@ -659,13 +659,13 @@ afp_setfork_err:
 /* ---------------------- */
 static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
 {
-    struct ofork       *ofork;
+    struct ofork    *ofork;
     off_t               offset, length;
     int                 eid;
-    u_int16_t          ofrefnum;
+    u_int16_t       ofrefnum;
     u_int8_t            flags;
     int                 lockop;
-    
+
     *rbuflen = 0;
 
     /* figure out parameters */
@@ -693,15 +693,15 @@ static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf
     /* FIXME AD_FILELOCK test is surely wrong */
     if (length == -1)
         length = BYTELOCK_MAX;
-     else if (!length || is_neg(is64, length)) {
-       return AFPERR_PARAM;
-     } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
+    else if (!length || is_neg(is64, length)) {
+        return AFPERR_PARAM;
+    } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
         return AFPERR_LOCK;
     }
 
     if (ENDBIT(flags)) {
         offset += ad_size(ofork->of_ad, eid);
-        /* FIXME what do we do if file size > 2 GB and 
+        /* FIXME what do we do if file size > 2 GB and
            it's not byte_lock_ext?
         */
     }
@@ -738,13 +738,13 @@ static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf
 /* --------------------------- */
 int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
 {
-   return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
+    return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
 }
 
 /* --------------------------- */
 int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
 {
-   return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
+    return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
 }
 
 #undef UNLOCKBIT
@@ -752,13 +752,13 @@ int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t
 /* --------------------------- */
 static int crlf(struct ofork *of)
 {
-    struct extmap      *em;
+    struct extmap   *em;
 
     if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
         /* no resource fork or no finderinfo, use our files extension mapping */
         if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
             return 0;
-        } 
+        }
         /* file type is TEXT */
         return 1;
 
@@ -770,9 +770,9 @@ static int crlf(struct ofork *of)
 
 
 static ssize_t read_file(struct ofork *ofork, int eid,
-                                    off_t offset, u_char nlmask,
-                                    u_char nlchar, char *rbuf,
-                                    size_t *rbuflen, const int xlate)
+                         off_t offset, u_char nlmask,
+                         u_char nlchar, char *rbuf,
+                         size_t *rbuflen, const int xlate)
 {
     ssize_t cc;
     int eof = 0;
@@ -825,7 +825,7 @@ static ssize_t read_file(struct ofork *ofork, int eid,
 }
 
 /* -----------------------------
- * with ddp, afp_read can return fewer bytes than in reqcount 
+ * with ddp, afp_read can return fewer bytes than in reqcount
  * so return EOF only if read actually past end of file not
  * if offset +reqcount > size of file
  * e.g.:
@@ -833,19 +833,19 @@ static ssize_t read_file(struct ofork *ofork, int eid,
  * read fork offset 0 size 10752 ????  ==> 4264 bytes (without EOF)
  * read fork offset 4264 size 6128 ==> 4264 (without EOF)
  * read fork offset 9248 size 1508 ==> 1182 (EOF)
- * 10752 is a bug in Mac 7.5.x finder 
+ * 10752 is a bug in Mac 7.5.x finder
  *
- * with dsi, should we check that reqcount < server quantum? 
-*/
+ * with dsi, should we check that reqcount < server quantum?
+ */
 static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
 {
-    struct ofork       *ofork;
-    off_t              offset, saveoff, reqcount, savereqcount;
-    ssize_t            cc, err;
-    int                        eid, xlate = 0;
-    u_int16_t          ofrefnum;
-    u_char             nlmask, nlchar;
-    
+    struct ofork    *ofork;
+    off_t       offset, saveoff, reqcount, savereqcount;
+    ssize_t     cc, err;
+    int         eid, xlate = 0;
+    u_int16_t       ofrefnum;
+    u_char      nlmask, nlchar;
+
     ibuf += 2;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
     ibuf += sizeof( u_short );
@@ -863,6 +863,11 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si
     offset   = get_off_t(&ibuf, is64);
     reqcount = get_off_t(&ibuf, is64);
 
+    LOG(log_debug, logtype_afpd,
+         "afp_read(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
+         cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
+         (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
     if (is64) {
         nlmask = nlchar = 0;
     }
@@ -901,7 +906,7 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si
         goto afp_read_err;
     }
 
-#define min(a,b)       ((a)<(b)?(a):(b))
+#define min(a,b)    ((a)<(b)?(a):(b))
     *rbuflen = min( reqcount, *rbuflen );
     err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
     if (err < 0)
@@ -919,8 +924,8 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si
         /* subtract off the offset */
         size -= offset;
         if (reqcount > size) {
-          reqcount = size;
-           err = AFPERR_EOF;
+            reqcount = size;
+            err = AFPERR_EOF;
         }
 
         offset += *rbuflen;
@@ -933,10 +938,10 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si
         *rbuflen = cc;
         /* due to the nature of afp packets, we have to exit if we get
            an error. we can't do this with translation on. */
-#ifdef WITH_SENDFILE 
+#ifdef WITH_SENDFILE
         if (!(xlate || Debug(obj) )) {
             int fd;
-                        
+
             fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
             if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
                 if (errno == EINVAL || errno == ENOSYS)
@@ -951,8 +956,8 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si
             goto afp_read_done;
         }
 
-afp_read_loop:
-#endif 
+    afp_read_loop:
+#endif
 
         /* fill up our buffer. */
         while (*rbuflen > 0) {
@@ -976,7 +981,7 @@ afp_read_loop:
         dsi_readdone(dsi);
         goto afp_read_done;
 
-afp_read_exit:
+    afp_read_exit:
         LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
         dsi_readdone(dsi);
         ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
@@ -1022,10 +1027,10 @@ int afp_flush(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, s
     return( AFP_OK );
 }
 
-int afp_flushfork(AFPObj *obj _U_, char        *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
+int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
-    struct ofork       *ofork;
-    u_int16_t          ofrefnum;
+    struct ofork    *ofork;
+    u_int16_t       ofrefnum;
 
     *rbuflen = 0;
     ibuf += 2;
@@ -1036,6 +1041,11 @@ int afp_flushfork(AFPObj *obj _U_, char  *ibuf, size_t ibuflen _U_, char *rbuf _U
         return( AFPERR_PARAM );
     }
 
+    LOG(log_debug, logtype_afpd,
+        "afp_flushfork(\"%s\", fork: %s)",
+        cfrombstr(ofork->of_ad->ad_fullpath),
+        (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
     if ( flushfork( ofork ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
     }
@@ -1048,7 +1058,7 @@ int afp_flushfork(AFPObj *obj _U_, char   *ibuf, size_t ibuflen _U_, char *rbuf _U
   There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
   fsync(2) on OSX is implemented differently than on other platforms.
   see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
- */
+*/
 int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
     struct ofork        *ofork;
@@ -1065,9 +1075,14 @@ int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_
         return( AFPERR_PARAM );
     }
 
+    LOG(log_debug, logtype_afpd,
+        "afp_syncfork(\"%s\", fork: %s)",
+        cfrombstr(ofork->of_ad->ad_fullpath),
+        (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
     if ( flushfork( ofork ) < 0 ) {
-       LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
-       return AFPERR_MISC;
+        LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
+        return AFPERR_MISC;
     }
 
     return( AFP_OK );
@@ -1081,14 +1096,14 @@ int flushfork(struct ofork *ofork)
     int err = 0, doflush = 0;
 
     if ( ad_data_fileno( ofork->of_ad ) != -1 &&
-            fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
+         fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
         LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
             of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
         err = -1;
     }
 
     if ( ad_reso_fileno( ofork->of_ad ) != -1 &&  /* HF */
-        (ofork->of_flags & AFPFORK_RSRC)) {
+         (ofork->of_flags & AFPFORK_RSRC)) {
 
         /* read in the rfork length */
         ad_refresh(ofork->of_ad);
@@ -1102,7 +1117,7 @@ int flushfork(struct ofork *ofork)
 
         /* flush the header */
         if (doflush && ad_flush(ofork->of_ad) < 0)
-                err = -1;
+            err = -1;
 
         if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
             err = -1;
@@ -1117,8 +1132,8 @@ int flushfork(struct ofork *ofork)
 
 int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
 {
-    struct ofork       *ofork;
-    u_int16_t          ofrefnum;
+    struct ofork    *ofork;
+    u_int16_t       ofrefnum;
 
     *rbuflen = 0;
     ibuf += 2;
@@ -1128,6 +1143,12 @@ int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U
         LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
         return( AFPERR_PARAM );
     }
+
+    LOG(log_debug, logtype_afpd,
+        "afp_closefork(\"%s\", fork: %s)",
+        cfrombstr(ofork->of_ad->ad_fullpath),
+        (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
     if ( of_closefork( ofork ) < 0 ) {
         LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
         return( AFPERR_PARAM );
@@ -1138,8 +1159,8 @@ int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U
 
 
 static ssize_t write_file(struct ofork *ofork, int eid,
-                                     off_t offset, char *rbuf,
-                                     size_t rbuflen, const int xlate)
+                          off_t offset, char *rbuf,
+                          size_t rbuflen, const int xlate)
 {
     char *p, *q;
     ssize_t cc;
@@ -1177,14 +1198,14 @@ static ssize_t write_file(struct ofork *ofork, int eid,
 
 
 /* FPWrite. NOTE: on an error, we always use afp_write_err as
- * the client may have sent us a bunch of data that's not reflected 
+ * the client may have sent us a bunch of data that's not reflected
  * in reqcount et al. */
 static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
 {
-    struct ofork       *ofork;
-    off_t              offset, saveoff, reqcount;
-    int                        endflag, eid, xlate = 0, err = AFP_OK;
-    u_int16_t          ofrefnum;
+    struct ofork    *ofork;
+    off_t               offset, saveoff, reqcount;
+    int             endflag, eid, xlate = 0, err = AFP_OK;
+    u_int16_t       ofrefnum;
     ssize_t             cc;
 
     /* figure out parameters */
@@ -1203,6 +1224,11 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s
         goto afp_write_err;
     }
 
+    LOG(log_debug, logtype_afpd,
+        "afp_write(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
+        cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
+        (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
     if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
         err = AFPERR_ACCESS;
         goto afp_write_err;
@@ -1233,7 +1259,7 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s
 
     /* offset can overflow on 64-bit capable filesystems.
      * report disk full if that's going to happen. */
-     if (sum_neg(is64, offset, reqcount)) {
+    if (sum_neg(is64, offset, reqcount)) {
         err = AFPERR_DFULL;
         goto afp_write_err;
     }
@@ -1278,59 +1304,59 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s
 #endif /* no afp/asp */
 
     case AFPPROTO_DSI:
-        {
-            DSI *dsi = obj->handle;
+    {
+        DSI *dsi = obj->handle;
+
+        /* find out what we have already and write it out. */
+        cc = dsi_writeinit(dsi, rbuf, *rbuflen);
+        if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
+            dsi_writeflush(dsi);
+            *rbuflen = 0;
+            ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
+            return cc;
+        }
+        offset += cc;
 
-            /* find out what we have already and write it out. */
-            cc = dsi_writeinit(dsi, rbuf, *rbuflen);
-            if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
+#if 0 /*def HAVE_SENDFILE_WRITE*/
+        if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
+            if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
+                                   offset, dsi->datasize)) < 0) {
+                switch (errno) {
+                case EDQUOT :
+                case EFBIG :
+                case ENOSPC :
+                    cc = AFPERR_DFULL;
+                    break;
+                default :
+                    LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
+                    goto afp_write_loop;
+                }
                 dsi_writeflush(dsi);
                 *rbuflen = 0;
-                ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
+                ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
+                           reqcount,  ofork->of_refnum);
                 return cc;
             }
-            offset += cc;
-
-#if 0 /*def HAVE_SENDFILE_WRITE*/
-            if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
-                if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
-                                       offset, dsi->datasize)) < 0) {
-                    switch (errno) {
-                    case EDQUOT :
-                    case EFBIG :
-                    case ENOSPC :
-                        cc = AFPERR_DFULL;
-                        break;
-                    default :
-                        LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
-                        goto afp_write_loop;
-                    }
-                    dsi_writeflush(dsi);
-                    *rbuflen = 0;
-                    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
-                               reqcount,  ofork->of_refnum);
-                    return cc;
-                }
 
-                offset += cc;
-                goto afp_write_done;
-            }
+            offset += cc;
+            goto afp_write_done;
+        }
 #endif /* 0, was HAVE_SENDFILE_WRITE */
 
-            /* loop until everything gets written. currently
-                    * dsi_write handles the end case by itself. */
-            while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
-                if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
-                    dsi_writeflush(dsi);
-                    *rbuflen = 0;
-                    ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
-                               reqcount,  ofork->of_refnum);
-                    return cc;
-                }
-                offset += cc;
+        /* loop until everything gets written. currently
+         * dsi_write handles the end case by itself. */
+        while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
+            if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
+                dsi_writeflush(dsi);
+                *rbuflen = 0;
+                ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
+                           reqcount,  ofork->of_refnum);
+                return cc;
             }
+            offset += cc;
         }
-        break;
+    }
+    break;
     }
 
     ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount,  ofork->of_refnum);
@@ -1357,9 +1383,9 @@ int afp_write(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbufl
     return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
 }
 
-/* ---------------------------- 
+/* ----------------------------
  * FIXME need to deal with SIGXFSZ signal
-*/
+ */
 int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
 {
     return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
@@ -1368,9 +1394,9 @@ int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *r
 /* ---------------------------- */
 int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
 {
-    struct ofork       *ofork;
+    struct ofork    *ofork;
     int             ret;
-    u_int16_t          ofrefnum, bitmap;
+    u_int16_t       ofrefnum, bitmap;
     size_t          buflen;
     ibuf += 2;
     memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
@@ -1393,7 +1419,7 @@ int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbu
     }
 
     if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
-                               rbuf + sizeof( u_short ), &buflen ))) {
+                                         rbuf + sizeof( u_short ), &buflen ))) {
         return( ret );
     }
 
index f5f8a38de8d7fff65a380ac83674fe9c755c190a..5a2449028074bd248e9e2a4f692dd0033a802159 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: ofork.c,v 1.32 2010/03/12 15:16:49 franklahm Exp $
- *
  * Copyright (c) 1996 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
  */
@@ -225,10 +223,6 @@ of_alloc(struct vol *vol,
             return NULL;
         }
         strlcpy( ad->ad_m_name, path, ad->ad_m_namelen);
-    } else {
-        /* Increase the refcount on this struct adouble. This is
-           decremented again in oforc_dealloc. */
-        ad->ad_refcount++;
     }
 
     of->of_ad = ad;
@@ -400,16 +394,7 @@ void of_dealloc( struct ofork *of)
 
     of_unhash(of);
     oforks[ of->of_refnum % nforks ] = NULL;
-
-    /* decrease refcount */
-    of->of_ad->ad_refcount--;
-
-    if ( of->of_ad->ad_refcount <= 0) {
-        free( of->of_ad->ad_m_name );
-        free( of->of_ad);
-    } else {/* someone's still using it. just free this user's locks */
-        ad_unlock(of->of_ad, of->of_refnum);
-    }
+    ad_unlock(of->of_ad, of->of_refnum);
 
     free( of );
 }
index 2203d257b65d953fe3fb65c27dca8a63de463dfc..456b86f433aef3cedbfc977225ff0e5e5eb20c68 100644 (file)
@@ -35,6 +35,7 @@
 #include <atalk/asp.h>
 #include <atalk/nbp.h>
 #include <atalk/unicode.h>
+#include <atalk/util.h>
 
 #include "globals.h"  /* includes <netdb.h> */
 #include "status.h"
@@ -90,14 +91,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 +378,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 +398,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..d5c0fba84b6cdd426f11458571509ed813f83162 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;
 
@@ -1497,7 +1487,7 @@ static int getvolparams( u_int16_t bitmap, struct vol *vol, struct stat *st, cha
      * .Parent file here if it doesn't exist. */
 
     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-    if ( ad_open_metadata( vol->v_path, ADFLAGS_DIR, O_CREAT, &ad) < 0 ) {
+    if (ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR, O_RDWR | O_CREAT, 0666) != 0 ) {
         isad = 0;
         vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime);
 
@@ -2507,8 +2497,7 @@ int afp_setvolparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf
         return AFPERR_BITMAP;
 
     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-    if ( ad_open( vol->v_path, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR,
-                  0666, &ad) < 0 ) {
+    if ( ad_open(&ad,  vol->v_path, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR) < 0 ) {
         if (errno == EROFS)
             return AFPERR_VLOCK;
 
@@ -2603,8 +2592,8 @@ static int create_special_folder (const struct vol *vol, const struct _special_f
     if ( !ret && folder->hide) {
         /* Hide it */
         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
-        if (ad_open_metadata( p, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
-            free (p);
+        if (ad_open(&ad, p, ADFLAGS_DIR, O_RDWR | O_CREAT, 0666) != 0) {
+            free(p);
             free(q);
             return (-1);
         }
index 240d4150d3312ef2dec686526e541f9b1a3ed0f3..7883268f2ced87ff12116cedf385d14b260cdf4c 100644 (file)
@@ -292,17 +292,16 @@ static const char *check_special_dirs(const char *name)
 */
 static int check_adfile(const char *fname, const struct stat *st)
 {
-    int ret, adflags;
+    int ret;
+    int adflags = ADFLAGS_HF;
     struct adouble ad;
-    char *adname;
+    const char *adname;
 
     if (dbd_flags & DBD_FLAGS_CLEANUP)
         return 0;
 
     if (S_ISREG(st->st_mode))
-        adflags = 0;
-    else
-        adflags = ADFLAGS_DIR;
+        adflags |= ADFLAGS_DIR;
 
     adname = myvolinfo->ad_path(fname, adflags);
 
@@ -322,7 +321,7 @@ static int check_adfile(const char *fname, const struct stat *st)
         /* Create ad file */
         ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
 
-        if ((ret = ad_open_metadata( fname, adflags, O_CREAT, &ad)) != 0) {
+        if ((ret = ad_open(&ad,  fname, adflags, O_CREAT | O_RDWR, 0666)) != 0) {
             dbd_log( LOGSTD, "Error creating AppleDouble file '%s/%s': %s",
                      cwdbuf, adname, strerror(errno));
 
@@ -341,7 +340,7 @@ static int check_adfile(const char *fname, const struct stat *st)
 #endif
     } else {
         ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
-        if (ad_open_metadata( fname, adflags, O_RDONLY, &ad) != 0) {
+        if (ad_open(&ad, fname, adflags, O_RDONLY) != 0) {
             dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s'", cwdbuf, fname);
             return -1;
         }
@@ -494,7 +493,7 @@ static int check_addir(int volroot)
         /* Create ad dir and set name */
         ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
 
-        if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad) != 0) {
+        if (ad_open(&ad, ".", ADFLAGS_HF | ADFLAGS_DIR, O_CREAT | O_RDWR, 0777) != 0) {
             dbd_log( LOGSTD, "Error creating AppleDouble dir in %s: %s", cwdbuf, strerror(errno));
             return -1;
         }
@@ -677,7 +676,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi
     ad_cnid = 0;
     if ( (myvolinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) {
         ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
-        if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) {
+        if (ad_open(&ad, name, adflags, O_RDWR) != 0) {
             
             if (dbd_flags & DBD_FLAGS_CLEANUP)
                 return 0;
@@ -773,7 +772,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi
                     dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file",
                             cwdbuf, name, ntohl(db_cnid));
                     ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
-                    if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) {
+                    if (ad_open(&ad, name, adflags, O_RDWR) != 0) {
                         dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s",
                                 cwdbuf, name, strerror(errno));
                         return 0;
@@ -811,7 +810,7 @@ static cnid_t check_cnid(const char *name, cnid_t did, struct stat *st, int adfi
                 dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file",
                         cwdbuf, name, ntohl(db_cnid));
                 ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
-                if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) {
+                if (ad_open(&ad, name, adflags, O_RDWR) != 0) {
                     dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s",
                             cwdbuf, name, strerror(errno));
                     return 0;
index 89355d767b8c0072a01d42763a935850b03e5a9c..e92adf03535970953743642c82ce0af29360a96c 100644 (file)
@@ -254,7 +254,7 @@ int comm_rcv(struct cnid_dbd_rqst *rqst, time_t timeout, const sigset_t *sigmask
         return -1;
     }
 
-    nametmp = rqst->name;
+    nametmp = (char *)rqst->name;
     if ((b = readt(cur_fd, rqst, sizeof(struct cnid_dbd_rqst), 1, CNID_DBD_TIMEOUT))
         != sizeof(struct cnid_dbd_rqst)) {
         if (b)
@@ -264,7 +264,7 @@ int comm_rcv(struct cnid_dbd_rqst *rqst, time_t timeout, const sigset_t *sigmask
         return 0;
     }
     rqst->name = nametmp;
-    if (rqst->namelen && readt(cur_fd, rqst->name, rqst->namelen, 1, CNID_DBD_TIMEOUT)
+    if (rqst->namelen && readt(cur_fd, (char *)rqst->name, rqst->namelen, 1, CNID_DBD_TIMEOUT)
         != rqst->namelen) {
         LOG(log_error, logtype_cnid, "error reading message name: %s", strerror(errno));
         invalidate_fd(cur_fd);
@@ -272,7 +272,7 @@ int comm_rcv(struct cnid_dbd_rqst *rqst, time_t timeout, const sigset_t *sigmask
     }
     /* We set this to make life easier for logging. None of the other stuff
        needs zero terminated strings. */
-    rqst->name[rqst->namelen] = '\0';
+    ((char *)(rqst->name))[rqst->namelen] = '\0';
 
     LOG(log_maxdebug, logtype_cnid, "comm_rcv: got %u bytes", b + rqst->namelen);
 
index a2efc33cfa6520071f302ee1f4947c4793638bf0..d932732d6c51238146a319479af2c7a93514c6eb 100644 (file)
@@ -29,7 +29,7 @@ int dbd_search(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
     rply->name = resbuf;
     rply->namelen = 0;
 
-    key.data = rqst->name;
+    key.data = (char *)rqst->name;
     key.size = rqst->namelen;
 
     if ((results = dbif_search(dbd, &key, resbuf)) < 0) {
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..d0813083dd8b359951edf0e8ac0fc253aa012d7a 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>
+#include <atalk/bstrlib.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 +57,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
+#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_NEWSZ2       (ADEDLEN_DID + ADEDLEN_AFPFILEI + ADEDLEN_SHORTNAME + ADEDLEN_PRODOSFILEI \
-                         + ADEDLEN_PRIVDEV + ADEDLEN_PRIVINO + ADEDLEN_PRIVSYN + ADEDLEN_PRIVID)
+#define AD_DATASZ_EA (AD_HEADER_LEN + (ADEID_NUM_EA * AD_ENTRY_LEN) + ADEDLEN_FINDERI + \
+                      ADEDLEN_COMMENT + ADEDLEN_FILEDATESI + ADEDLEN_AFPFILEI + ADEDLEN_PRIVID)
 
-/* 725 */
-#define AD_DATASZ2      (AD_DATASZ1 + AD_NEWSZ2 + ((ADEID_NUM_V2 - ADEID_NUM_V1) * AD_ENTRY_LEN))
-
-#if AD_DATASZ2 != 741
-#error bad size for AD_DATASZ2
+#if AD_DATASZ_EA != 342
+#error bad size for AD_DATASZ_EA
 #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
+
+#if AD_VERSION == AD_VERSION2
 #define AD_DATASZ   AD_DATASZ2
+#elif AD_VERSION == AD_VERSION_EA
+#define AD_DATASZ   AD_DATASZ_EA
 #endif
 
-/*
- * some legacy defines from netatalk-990130
- * (to keep from breaking certain packages)
- *
- */
-
-#define ADEDOFF_RFORK   589
-#define ADEDOFF_NAME    86
-#define ADEDOFF_COMMENT 341
-#define ADEDOFF_FINDERI 557
-#ifndef ADEDOFF_FILEI
-#define ADEDOFF_FILEI   541
-#endif
+#define RFORK_EA_ALLOCSIZE (128*1024) /* 128k */
 
 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,21 +157,30 @@ 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;
+#if 0
     adf_lock_t   *adf_lock;
     int          adf_refcount, adf_lockcount, adf_lockmax;
+#endif
 };
 
 /* some header protection */
 #define AD_INITED  0xad494e54  /* ad"INT" */
-struct adouble_fops;
+
+struct adouble;
+
+struct adouble_fops {
+    const char *(*ad_path)(const char *, int);
+    int  (*ad_mkrf)(const char *);
+    int  (*ad_rebuild_header)(struct adouble *);
+    int  (*ad_header_read)(struct adouble *, struct stat *);
+    int  (*ad_header_upgrade)(struct adouble *, const char *);
+};
 
 struct adouble {
     u_int32_t           ad_magic;
@@ -266,52 +189,29 @@ 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;
     int                 ad_options;
-    int                 ad_fileordir;
-    int                 ad_refcount; /* used in afpd/ofork.c */
+    void                *ad_resforkbuf;  /* buffer for AD_VERSION_EA ressource fork */
+    size_t              ad_resforkbufsize; /* size of ad_resforkbuf */
     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;
+    bstring             ad_fullpath; /* adouble EA need this */
     struct adouble_fops *ad_ops;
-    u_int16_t       ad_open_forks;      /* open forks (by others) */
-
-#ifdef USE_MMAPPED_HEADERS
-    char                *ad_data;
-#else
-    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 *);
+    uint16_t            ad_open_forks; /* open forks (by others) */
+    char                ad_data[AD_DATASZ_MAX];
 };
 
 #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_OPENFORKS (1<<5)  /* check for open fork in ad_metadata function */
+
 #define ADVOL_NODEV      (1 << 0)
 #define ADVOL_CACHE      (1 << 1)
 #define ADVOL_UNIXPRIV   (1 << 2) /* adouble unix priv */
@@ -462,27 +362,29 @@ extern int ad_excl_lock     (struct adouble * /*adp*/, const u_int32_t /*eid*/);
 #define ad_unlock ad_fcntl_unlock
 
 /* ad_open.c */
+extern const char *oflags2logstr(int oflags);
+extern const char *adflags2logstr(int adflags);
 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 const char *ad_path      (const char *, int);
+extern const 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 );
-extern int ad_open        (const char *, int, int, int, struct adouble *);
-extern int ad_openat      (int dirfd, const char *, int, int, int, struct adouble *);
+extern int ad_open        (struct adouble *ad, const char *path, int adflags, ...);
+extern int ad_openat      (struct adouble *, int dirfd, const char *path, int adflags, ...);
 extern int ad_refresh     (struct adouble *);
 extern int ad_stat        (const char *, struct stat *);
 extern int ad_metadata    (const char *, int, struct adouble *);
 extern int ad_metadataat  (int, const char *, int, struct adouble *);
 
+#if 0
 #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))
+#endif
 
-#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 +411,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 d7df70e1d164ddd82c5c61f44f9e07996500607a..2c673fbcccf2c63e77d088982e1203ae3e13e90c 100644 (file)
@@ -53,21 +53,21 @@ struct _cnid_db {
     char *volpath;               /* Volume path this particular CNID db refers to. */
     void *_private;              /* back-end speficic data */
 
-    cnid_t (*cnid_add)         (struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
-                                char *name, const size_t, cnid_t hint);
+    cnid_t (*cnid_add)         (struct _cnid_db *cdb, const struct stat *st, cnid_t did,
+                                const char *name, size_t, cnid_t hint);
     int    (*cnid_delete)      (struct _cnid_db *cdb, cnid_t id);
-    cnid_t (*cnid_get)         (struct _cnid_db *cdb, const cnid_t did, char *name, const  size_t);
-    cnid_t (*cnid_lookup)      (struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
-                                char *name, const size_t);
+    cnid_t (*cnid_get)         (struct _cnid_db *cdb, cnid_t did, const char *name, size_t);
+    cnid_t (*cnid_lookup)      (struct _cnid_db *cdb, const struct stat *st, cnid_t did,
+                                const char *name, size_t);
     cnid_t (*cnid_nextid)      (struct _cnid_db *cdb);
     char * (*cnid_resolve)     (struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len);
-    int    (*cnid_update)      (struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
-                                const cnid_t did, char *name, const size_t len);
+    int    (*cnid_update)      (struct _cnid_db *cdb, cnid_t id, const struct stat *st,
+                                cnid_t did, const char *name, size_t len);
     void   (*cnid_close)       (struct _cnid_db *cdb);
     int    (*cnid_getstamp)    (struct _cnid_db *cdb, void *buffer, const size_t len);
-    cnid_t (*cnid_rebuild_add) (struct _cnid_db *, const struct stat *, const cnid_t,
-                                char *, const size_t, cnid_t);
-    int    (*cnid_find)        (struct _cnid_db *cdb, char *name, size_t namelen,
+    cnid_t (*cnid_rebuild_add) (struct _cnid_db *, const struct stat *, cnid_t,
+                                const char *, size_t, cnid_t);
+    int    (*cnid_find)        (struct _cnid_db *cdb, const char *name, size_t namelen,
                                 void *buffer, size_t buflen);
 };
 typedef struct _cnid_db cnid_db;
index 36dee3d8264890402fa6cc7b0f7d233c08efa706..e1464125559be481d431168b3541f29394bc4200 100644 (file)
@@ -43,7 +43,7 @@ struct cnid_dbd_rqst {
     ino_t   ino;
     uint32_t type;
     cnid_t  did;
-    char    *name;
+    const char *name;
     size_t  namelen;
 };
 
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..f26e32b288f0171058159a9979f5474465175039 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,27 @@ 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"
+#define NOT_NETATALK_EA(a) (strcmp((a), AD_EA_META) != 0) && (strcmp((a), AD_EA_RESO) != 0)
+
+/****************************************************************************************
+ * 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 2e75b461b53c0ab198b2a8f44aecf08057c32ea3..bd4bed72ae0add8502896f900619021fa45e22f3 100644 (file)
 /* lock file path. this should be re-organized a bit. */
 #if ! defined (_PATH_LOCKDIR)
 #  if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
-#    define _PATH_LOCKDIR      "/var/run/"
+#    define _PATH_LOCKDIR      /var/run/
 #  elif defined (BSD4_4)
 #    ifdef MACOSX_SERVER
-#      define _PATH_LOCKDIR    "/var/run/"
+#      define _PATH_LOCKDIR    /var/run/
 #    else
-#      define _PATH_LOCKDIR    "/var/spool/lock/"
+#      define _PATH_LOCKDIR    /var/spool/lock/
 #    endif
 #  elif defined (linux)
-#    define _PATH_LOCKDIR      "/var/lock/"
+#    define _PATH_LOCKDIR      /var/lock/
 #  else
-#    define _PATH_LOCKDIR      "/var/spool/locks/"
+#    define _PATH_LOCKDIR      /var/spool/locks/
 #  endif
 #endif
 
@@ -52,9 +52,9 @@
 #define _PATH_ATALKDEBUG       "/tmp/atalkd.debug"
 #define _PATH_ATALKDTMP                "atalkd.tmp"
 #if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
-#  define _PATH_ATALKDLOCK     ATALKPATHCAT(_PATH_LOCKDIR,"atalkd.pid")
+#  define _PATH_ATALKDLOCK     ATALKPATHCAT("_PATH_LOCKDIR","atalkd.pid")
 #else
-#  define _PATH_ATALKDLOCK     ATALKPATHCAT(_PATH_LOCKDIR,"atalkd")
+#  define _PATH_ATALKDLOCK     ATALKPATHCAT("_PATH_LOCKDIR","atalkd")
 #endif
 
 /*
@@ -62,9 +62,9 @@
  */
 #define _PATH_TMPPAGEORDER     "/tmp/psorderXXXXXX"
 #if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
-#  define _PATH_PAPDLOCK       ATALKPATHCAT(_PATH_LOCKDIR,"papd.pid")
+#  define _PATH_PAPDLOCK       ATALKPATHCAT("_PATH_LOCKDIR","papd.pid")
 #else
-#  define _PATH_PAPDLOCK       ATALKPATHCAT(_PATH_LOCKDIR,"papd")
+#  define _PATH_PAPDLOCK       ATALKPATHCAT("_PATH_LOCKDIR","papd")
 #endif
 
 /*
  */
 #define _PATH_AFPTKT           "/tmp/AFPtktXXXXXX"
 #if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
-#  define _PATH_AFPDLOCK       ATALKPATHCAT(_PATH_LOCKDIR,"afpd.pid")
+#  define _PATH_AFPDLOCK       ATALKPATHCAT("_PATH_LOCKDIR","afpd.pid")
 #else
-#  define _PATH_AFPDLOCK       ATALKPATHCAT(_PATH_LOCKDIR,"afpd")
+#  define _PATH_AFPDLOCK       ATALKPATHCAT("_PATH_LOCKDIR","afpd")
 #endif
 
 /*
  * cnid_metad paths
  */
 #if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
-#  define _PATH_CNID_METAD_LOCK        ATALKPATHCAT(_PATH_LOCKDIR,"cnid_metad.pid")
+#  define _PATH_CNID_METAD_LOCK        ATALKPATHCAT("_PATH_LOCKDIR","cnid_metad.pid")
 #else
-#  define _PATH_CNID_METAD_LOCK        ATALKPATHCAT(_PATH_LOCKDIR,"cnid_metad")
+#  define _PATH_CNID_METAD_LOCK        ATALKPATHCAT("_PATH_LOCKDIR","cnid_metad")
 #endif
 
 #endif /* atalk/paths.h */
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 e3b2be118b19cb317694cad350e55c158809c8a5..ddc2e3bd5e8be73f989015a748a706d0f8eaf08e 100644 (file)
@@ -18,7 +18,7 @@
 #define UUID_BINSIZE 16
 #define UUID_STRINGSIZE 36
 
-typedef unsigned char *uuidp_t;
+typedef const unsigned char *uuidp_t;
 typedef unsigned char atalk_uuid_t[UUID_BINSIZE];
 
 typedef enum {UUID_USER = 1, UUID_GROUP, UUID_LOCAL} uuidtype_t;
@@ -40,9 +40,9 @@ extern char *ldap_uid_attr;
  * Interface
  ********************************************************/
 
-extern int getuuidfromname( const char *name, uuidtype_t type, uuidp_t uuid);
-extern int getnamefromuuid( const uuidp_t uuidp, char **name, uuidtype_t *type);
-extern const char *uuid_bin2string(unsigned char *uuid);
-extern void uuid_string2bin( const char *uuidstring, uuidp_t uuid);
+extern int getuuidfromname( const char *name, uuidtype_t type, unsigned char *uuid);
+extern int getnamefromuuid( uuidp_t uuidp, char **name, uuidtype_t *type);
+extern const char *uuid_bin2string(const unsigned char *uuid);
+extern void uuid_string2bin( const char *uuidstring, unsigned char *uuid);
 
 #endif /* AFP_UUID_H */
index 0f3a4024a6a36faedc4993783a731369e56237b3..1124b1391171689042544a6985fb872424521bde 100644 (file)
@@ -30,7 +30,7 @@ struct volinfo {
     int                 v_adouble;  /* default adouble format */
     int                 v_ad_options;
     int                 v_vfs_ea;
-    char                *(*ad_path)(const char *, int);
+    const char          *(*ad_path)(const char *, int);
     char                *v_dbd_host;
     char                *v_dbd_port;
 };
index 77966459b2618f69d3cff16faeae7680a00bb9e0..f213502d7111bb9dc97352d7b17f452c82ecafa0 100644 (file)
@@ -40,7 +40,7 @@ struct vol {
     char            *v_veto;
     int             v_adouble;    /* adouble format: v1, v2, sfm ... */
     int             v_ad_options; /* adouble option NODEV, NOCACHE, etc.. */
-    char            *(*ad_path)(const char *, int);
+    const char      *(*ad_path)(const char *, int);
     struct _cnid_db *v_cdb;
     char            v_stamp[ADEDLEN_PRIVSYN];
     VolSpace        v_limitsize; /* Size limit, if any, in MiB */
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 4c640ac25ff425a0e27724e804749fd93ceed916..60ae653a44b6cd1e832565d344f3c3455395dfc7 100644 (file)
@@ -30,7 +30,7 @@
 typedef struct cacheduser {
     unsigned long uid;      /* for future use */
     uuidtype_t type;
-    uuidp_t uuid;
+    unsigned char *uuid;
     char *name;
     time_t creationtime;
     struct cacheduser *prev;
@@ -117,7 +117,7 @@ static unsigned char hashuuid(uuidp_t uuid) {
 int add_cachebyname( const char *inname, const uuidp_t inuuid, const uuidtype_t type, const unsigned long uid _U_) {
     int ret = 0;
     char *name = NULL;
-    uuidp_t uuid;
+    unsigned char *uuid;
     cacheduser_t *cacheduser = NULL;
     cacheduser_t *entry;
     unsigned char hash;
@@ -193,7 +193,7 @@ cleanup:
 /* 
  * Caller provides buffer uuid for result
  */
-int search_cachebyname( const char *name, uuidtype_t type, uuidp_t uuid) {
+int search_cachebyname( const char *name, uuidtype_t type, unsigned char *uuid) {
     int ret;
     unsigned char hash;
     cacheduser_t *entry;
@@ -307,7 +307,7 @@ int search_cachebyuuid( uuidp_t uuidp, char **name, uuidtype_t *type) {
 int add_cachebyuuid( uuidp_t inuuid, const char *inname, uuidtype_t type, const unsigned long uid _U_) {
     int ret = 0;
     char *name = NULL;
-    uuidp_t uuid;
+    unsigned char *uuid;
     cacheduser_t *cacheduser = NULL;
     cacheduser_t *entry;
     unsigned char hash;
index 7db8ecdc92453930e721232fba2d82db32652d78..c83be1cd16dbd4a2152724c2343838b6a0f15d90 100644 (file)
@@ -38,7 +38,7 @@
  *   uuid: if found copies uuid into this buffer
  * returns 0 on success, !=0 if not found or on errors
  */
-extern int search_cachebyname( const char *name, uuidtype_t type, uuidp_t uuid);
+extern int search_cachebyname( const char *name, uuidtype_t type, unsigned char *uuid);
 
 /* 
  *   inname: name
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 8993acc21f61fa38bc0c58dda11bd720eebc0cf4..fb085b2379997283b9649ca3aed383d944192e3a 100644 (file)
@@ -43,7 +43,7 @@ char *uuidtype[] = {"NULL","USER", "GROUP", "LOCAL"};
  * convert ascii string that can include dashes to binary uuid.
  * caller must provide a buffer.
  */
-void uuid_string2bin( const char *uuidstring, uuidp_t uuid) {
+void uuid_string2bin( const char *uuidstring, unsigned char *uuid) {
     int nibble = 1;
     int i = 0;
     unsigned char c, val = 0;
@@ -77,7 +77,7 @@ void uuid_string2bin( const char *uuidstring, uuidp_t uuid) {
  * 
  * Returns pointer to static buffer.
  */
-const char *uuid_bin2string(unsigned char *uuid) {
+const char *uuid_bin2string(const unsigned char *uuid) {
     static char uuidstring[UUID_STRINGSIZE + 1];
 
     int i = 0;
@@ -113,7 +113,7 @@ static unsigned char local_user_uuid[] = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd,
  *   uuid: pointer to uuid_t storage that the caller must provide
  * returns 0 on success !=0 on errror
  */  
-int getuuidfromname( const char *name, uuidtype_t type, uuidp_t uuid) {
+int getuuidfromname( const char *name, uuidtype_t type, unsigned char *uuid) {
     int ret = 0;
 #ifdef HAVE_LDAP
     char *uuid_string = NULL;
@@ -183,7 +183,7 @@ cleanup:
  *
  * Caller must free name appropiately.
  */
-int getnamefromuuid(const uuidp_t uuidp, char **name, uuidtype_t *type) {
+int getnamefromuuid(uuidp_t uuidp, char **name, uuidtype_t *type) {
     int ret;
 
     ret = search_cachebyuuid( uuidp, name, type);
index 8a242c2a87679e775aa3773c3d335f02ad6d49f6..6602926b6328986453cb395bbb9c476bdf582aca 100644 (file)
@@ -5,4 +5,4 @@ noinst_LTLIBRARIES = libadouble.la
 libadouble_la_SOURCES = ad_open.c ad_flush.c ad_read.c ad_write.c ad_size.c \
        ad_mmap.c ad_lock.c ad_date.c ad_attr.c ad_sendfile.c
 
-noinst_HEADERS = ad_private.h
+noinst_HEADERS = ad_lock.h
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..da6bcc29ab292566581f6a34a69427854142d447 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>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
 
-#else
+#include "ad_lock.h"
 
 static const u_int32_t set_eid[] = {
     0,1,2,3,4,5,6,7,8,
@@ -46,22 +46,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 +68,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 +91,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,110 +143,86 @@ 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 );
+            }
+            break;
+        case AD_VERSION_EA:
+            if (sys_lsetxattr(cfrombstr(ad->ad_fullpath), 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;
             }
-            return( -1 );
+            break;
+        default:
+            LOG(log_error, logtype_afpd, "ad_flush: unexpected adouble version");
+            return -1;
         }
     }
 
     return( 0 );
 }
 
-/* use refcounts so that we don't have to re-establish fcntl locks. */
+/*!
+ * Close a struct adouble freeing all resources
+ *
+ * This close the whole thing, regardless of what you pass in adflags!
+ */
 int ad_close( struct adouble *ad, int adflags)
 {
-    int         err = 0;
+    int err = 0;
 
-    if ((adflags & ADFLAGS_DF)
-        && (ad_data_fileno(ad) >= 0 || ad_data_fileno(ad) == -2) /* -2 means symlink */
-        && --ad->ad_data_fork.adf_refcount == 0) {
-        if (ad->ad_data_fork.adf_syml != NULL) {
+    LOG(log_debug, logtype_default, "ad_close(\"%s\", %s)",
+        cfrombstr(ad->ad_fullpath),
+        adflags2logstr(adflags));
+
+    if (ad_data_fileno(ad) != -1) {
+        if ((ad_data_fileno(ad) == -2) && (ad->ad_data_fork.adf_syml != NULL)) {
             free(ad->ad_data_fork.adf_syml);
-            ad->ad_data_fork.adf_syml = 0;
+            ad->ad_data_fork.adf_syml = NULL;
         } else {
             if ( close( ad_data_fileno(ad) ) < 0 )
                 err = -1;
         }
         ad_data_fileno(ad) = -1;
         adf_lock_free(&ad->ad_data_fork);
+        ad->ad_adflags &= ~ADFLAGS_DF;
     }
 
-    if (!( adflags & ADFLAGS_HF )) {
-        return err;
-    }
-
-    /* meta /resource fork */
-
-    if ( ad_meta_fileno(ad) != -1 && !(--ad->ad_md->adf_refcount)) {
-        if ( close( ad_meta_fileno(ad) ) < 0 ) {
+    if (ad_meta_fileno(ad) != -1) {
+        if ( close( ad_meta_fileno(ad) ) < 0 )
             err = -1;
-        }
         ad_meta_fileno(ad) = -1;
         adf_lock_free(ad->ad_md);
+        ad->ad_adflags &= ~ADFLAGS_HF;
     }
 
-    if (ad->ad_flags != AD_VERSION1_SFM) {
-        return err;
+    if (ad->ad_resforkbuf) {
+        free(ad->ad_resforkbuf);
+        ad->ad_resforkbuf = NULL;
+        ad->ad_adflags &= ~ADFLAGS_RF;
     }
 
-    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);
+    if (ad->ad_fullpath) {
+        bdestroy(ad->ad_fullpath);
+        ad->ad_fullpath = NULL;
     }
 
     return err;
index 30a1303340c6fdef00a885c63d0ea00f5a7b8199..28b53b12edddc66842dfcf10e0fd79d2464b50e9 100644 (file)
@@ -26,7 +26,7 @@
 
 #include <string.h>
 
-#include "ad_private.h"
+#include "ad_lock.h"
 
 /* translate between ADLOCK styles and specific locking mechanisms */
 #define XLATE_FLOCK(type) ((type) == ADLOCK_RD ? LOCK_SH : \
@@ -66,9 +66,9 @@ static int XLATE_FCNTL_LOCK(int type)
 /* ----------------------- */
 static int OVERLAP(off_t a, off_t alen, off_t b, off_t blen) 
 {
- return (!alen && a <= b) || 
-       (!blen && b <= a) || 
-       ( (a + alen > b) && (b + blen > a) );
   return (!alen && a <= b) || 
+        (!blen && b <= a) || 
+        ( (a + alen > b) && (b + blen > a) );
 }
 
 /* allocation for lock regions. we allocate aggressively and shrink
@@ -79,6 +79,7 @@ static int OVERLAP(off_t a, off_t alen, off_t b, off_t blen)
 /* remove a lock and compact space if necessary */
 static void adf_freelock(struct ad_fd *ad, const int i)
 {
+#if 0
     adf_lock_t *lock = ad->adf_lock + i;
 
     if (--(*lock->refcount) < 1) {
@@ -111,6 +112,7 @@ static void adf_freelock(struct ad_fd *ad, const int i)
                ad->adf_lockmax = ad->adf_lockcount + ARRAY_FREE_DELTA;
            }
     }
+#endif
 }
 
 
@@ -123,6 +125,7 @@ static void adf_freelock(struct ad_fd *ad, const int i)
  */
 static void adf_unlock(struct ad_fd *ad, const int fork)
 {
+#if 0
     adf_lock_t *lock = ad->adf_lock;
     int i;
 
@@ -137,13 +140,14 @@ static void adf_unlock(struct ad_fd *ad, const int fork)
         lock = ad->adf_lock;       
       }
     }
+#endif
 }
 
 /* relock any byte lock that overlaps off/len. unlock everything
  * else. */
-static void adf_relockrange(struct ad_fd *ad, int fd,
-                                      const off_t off, const off_t len)
+static void adf_relockrange(struct ad_fd *ad, int fd, off_t off, off_t len)
 {
+#if 0
     adf_lock_t *lock = ad->adf_lock;
     int i;
     
@@ -151,15 +155,17 @@ static void adf_relockrange(struct ad_fd *ad, int fd,
       if (OVERLAP(off, len, lock[i].lock.l_start, lock[i].lock.l_len)) 
        set_lock(fd, F_SETLK, &lock[i].lock);
     }
+#endif
 }
 
 
 /* find a byte lock that overlaps off/len for a particular open fork */
 static int adf_findlock(struct ad_fd *ad,
-                                  const int fork, const int type,
-                                  const off_t off,
-                                  const off_t len)
+                        const int fork, const int type,
+                        const off_t off,
+                        const off_t len)
 {
+#if 0
   adf_lock_t *lock = ad->adf_lock;
   int i;
   
@@ -171,17 +177,18 @@ static int adf_findlock(struct ad_fd *ad,
       return i;
     }
   }
-
+#endif
   return -1;
 }
 
 
 /* search other fork lock lists */
 static int adf_findxlock(struct ad_fd *ad, 
-                                    const int fork, const int type,
-                                    const off_t off,
-                                    const off_t len)
+                         const int fork, const int type,
+                         const off_t off,
+                         const off_t len)
 {
+#if 0
   adf_lock_t *lock = ad->adf_lock;
   int i;
   
@@ -192,6 +199,7 @@ static int adf_findxlock(struct ad_fd *ad,
        OVERLAP(off, len, lock[i].lock.l_start, lock[i].lock.l_len)) 
            return i;
   } 
+#endif
   return -1;
 }
 
@@ -262,8 +270,9 @@ int start = off;
 
 /* ------------------ */
 int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int locktype,
-                 const off_t off, const off_t len, const int fork)
+                  const off_t off, const off_t len, const int fork)
 {
+#if 0
   struct flock lock;
   struct ad_fd *adf;
   adf_lock_t *adflock;
@@ -401,6 +410,8 @@ fcntl_lock_err:
   lock.l_type = F_UNLCK;
   if (!adf->adf_excl) set_lock(adf->adf_fd, F_SETLK, &lock);
   return -1;
+#endif
+  return 0;
 }
 
 /* -------------------------
@@ -413,6 +424,7 @@ fcntl_lock_err:
 */
 static int testlock(struct ad_fd *adf, off_t off, off_t len)
 {
+#if 0
   struct flock lock;
   adf_lock_t *plock;
   int i;
@@ -441,11 +453,15 @@ static int testlock(struct ad_fd *adf, off_t off, off_t len)
       return 0;
   }
   return 1;
+#endif
+  return 0;
 }
 
 /* --------------- */
 int ad_testlock(struct adouble *ad, int eid, const off_t off)
 {
+    return 0;
+#if 0
   struct ad_fd *adf;
   off_t      lock_offset;
 
@@ -466,6 +482,7 @@ int ad_testlock(struct adouble *ad, int eid, const off_t off)
     lock_offset = hf2off(off);
   }
   return testlock(adf, lock_offset, 1);
+#endif
 }
 
 /* -------------------------
@@ -476,6 +493,8 @@ int ad_testlock(struct adouble *ad, int eid, const off_t off)
 */
 u_int16_t ad_openforks(struct adouble *ad, u_int16_t attrbits)
 {
+    return 0;
+#if 0
   u_int16_t ret = 0;
   struct ad_fd *adf;
   off_t off;
@@ -527,6 +546,7 @@ u_int16_t ad_openforks(struct adouble *ad, u_int16_t attrbits)
   }
 
   return ret;
+#endif
 }
 
 /* -------------------------
@@ -534,6 +554,8 @@ u_int16_t ad_openforks(struct adouble *ad, u_int16_t attrbits)
 int ad_fcntl_tmplock(struct adouble *ad, const u_int32_t eid, const int locktype,
                     const off_t off, const off_t len, const int fork)
 {
+    return 0;
+#if 0
   struct flock lock;
   struct ad_fd *adf;
   int err;
@@ -592,6 +614,7 @@ int ad_fcntl_tmplock(struct adouble *ad, const u_int32_t eid, const int locktype
     adf_relockrange(adf, adf->adf_fd, lock.l_start, len);
 
   return err;
+#endif
 }
 
 /* -------------------------
@@ -600,6 +623,8 @@ int ad_fcntl_tmplock(struct adouble *ad, const u_int32_t eid, const int locktype
 */
 int ad_excl_lock(struct adouble *ad, const u_int32_t eid)
 {
+    return 0;
+#if 0
   struct ad_fd *adf;
   struct flock lock;
   int    err;
@@ -620,11 +645,14 @@ int ad_excl_lock(struct adouble *ad, const u_int32_t eid)
   if (!err)
       adf->adf_excl = 1;
   return err;
+#endif
 }
 
 /* --------------------- */
 void ad_fcntl_unlock(struct adouble *ad, const int fork)
 {
+    return;
+#if 0
   if (ad_data_fileno(ad) != -1) {
     adf_unlock(&ad->ad_data_fork, fork);
   }
@@ -632,11 +660,11 @@ 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) {
     adf_unlock(&ad->ad_metadata_fork, fork);
   }
-
+#endif
 }
diff --git a/libatalk/adouble/ad_lock.h b/libatalk/adouble/ad_lock.h
new file mode 100644 (file)
index 0000000..8e7860d
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef LIBATALK_ADOUBLE_AD_PRIVATE_H
+#define LIBATALK_ADOUBLE_AD_PRIVATE_H 1
+
+#include <atalk/adouble.h>
+
+/* this is so that we can keep lists of fds referencing the same file
+ * around. that way, we can honor locks created by the same process
+ * with the same file. */
+
+#define adf_lock_free(a)                                      \
+    do {                                                      \
+        ;                                                     \
+    } while (0)
+
+#endif /* libatalk/adouble/ad_private.h */
index 2cb5c05937f2f6d69470996bea5994eaaf069e2b..a93ab5a502dfa64a7f826160457b4fa61d93b304 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: ad_mmap.c,v 1.6 2008-12-03 18:35:44 didg Exp $
- *
  * ad_mmap provides interfaces to memory mapped files. as this is the
  * case, we don't have to deal w/ temporary buffers such as
  * ad_data. the ad_mmap routines are designed to not interact w/ the
@@ -17,7 +15,7 @@
 #include <atalk/adouble.h>
 #include <string.h>
 
-#include "ad_private.h"
+#include "ad_lock.h"
 
 static void *ad_mmap(const size_t length, const int prot,
                                const int flags, const int fd, 
index 7adb4abda262c7261a8197463d36f9369a2a7426..6bc1b3305b17060e610801326b1bf34f135884d7 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 <stdarg.h>
 
+#include <atalk/logger.h>
+#include <atalk/adouble.h>
 #include <atalk/util.h>
-#include <string.h>
+#include <atalk/ea.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
 
-#include "ad_private.h"
-#include <stdlib.h>
+#include "ad_lock.h"
 
 #ifndef MAX
 #define MAX(a, b)  ((a) < (b) ? (b) : (a))
 #endif /* ! MAX */
 
-/*
- * AppleDouble entry default offsets.
- * The layout looks like this:
- *
- * this is the v1 layout:
- *     255         200         16          32          N
- *  |  NAME |    COMMENT    | FILEI |    FINDERI    | RFORK |
- *
- * we need to change it to look like this:
- *
- * v2 layout:
- * field       length (in bytes)
- * NAME        255
- * COMMENT     200
- * FILEDATESI  16     replaces FILEI
- * FINDERI     32
- * DID          4     new
- * AFPFILEI     4     new
- * SHORTNAME   12     8.3 new
- * RFORK        N
- *
- * 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.
- */
+#ifdef  HAVE_PREAD
+# define AD_SET(a)
+#else
+# define AD_SET(a) a = 0
+#endif
 
 #define ADEDOFF_MAGIC        (0)
 #define ADEDOFF_VERSION      (ADEDOFF_MAGIC + ADEDLEN_MAGIC)
 /* initial lengths of some of the fields */
 #define ADEDLEN_INIT     0
 
-/* make sure we don't redefine ADEDOFF_FILEI */
-#ifdef ADEDOFF_FILEI
-#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(const char *path);
+static int ad_header_read(struct adouble *ad, struct stat *hst);
+static int ad_header_upgrade(struct adouble *ad, const char *name);
+
+static int ad_mkrf_ea(const char *path);
+static int ad_header_read_ea(struct adouble *ad, struct stat *hst);
+static int ad_header_upgrade_ea(struct adouble *ad, const char *name);
+
+static struct adouble_fops ad_adouble = {
+    &ad_path,
+    &ad_mkrf,
+    &ad_rebuild_adouble_header,
+    &ad_header_read,
+    &ad_header_upgrade,
+};
+
+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,
 };
 
-#if AD_VERSION == AD_VERSION1
-#define DISK_EID(ad, a) (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}
+};
 
-#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)
+static 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 +173,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 +254,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 +277,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 +290,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 +311,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 +323,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 +340,479 @@ 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_lgetxattr(cfrombstr(ad->ad_fullpath), 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 ));
-
-    /* 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++;
-        }
+    memcpy(&ad->ad_version, buf + ADEDOFF_VERSION, sizeof( 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) )) {
+    ad->ad_magic = ntohl( ad->ad_magic );
+    ad->ad_version = ntohl( ad->ad_version );
+
+    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(const 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(const 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++] = '/';
+   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;
+}
+
+#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)
+{
+    if (*mode == 0) {
+        return -1;
+    }
+    if (ad_stat(path, stbuf) != 0) {
+        *mode &= DEFMASK;
+        return -1;
+    }
+    *mode &= stbuf->st_mode;
+    return 0;
+}
+
+/* --------------------------- */
+static int ad_header_upgrade(struct adouble *ad _U_, const char *name _U_)
+{
+    return 0;
+}
+
+static int ad_header_upgrade_ea(struct adouble *ad _U_, const char *name _U_)
+{
+    AFP_PANIC("ad_header_upgrade_ea: dont use");
+    return 0;
+}
+
+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);
         }
-        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;
+        /* 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;
         }
-        l += strlcpy( pathbuf +l, ".AppleDouble/", sizeof(pathbuf) -l);
-        strlcpy( pathbuf + l, slash, sizeof(pathbuf) -l);
+        /* 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.
+         */
     }
 
-    return( pathbuf );
+    return 0;
 }
 
-/* -------------------- */
-static int ad_mkrf(char *path)
+static int ad_open_hf_v2(const char *path, int adflags, int oflags, int mode, struct adouble *ad)
 {
-    char *slash;
-    /*
-     * Probably .AppleDouble doesn't exist, try to mkdir it.
-     */
-    if (NULL == ( slash = strrchr( path, '/' )) ) {
-        return -1;
+    struct stat st_dir;
+    struct stat st_meta;
+    struct stat *pst = NULL;
+    const 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)) | O_NOFOLLOW;
+
+    ad->ad_md->adf_fd = open(ad_p, hoflags, 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\"): creating adouble file",
+                abspath(path));
+            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 -1;
+                }
+                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 -1;
+            }
+            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 -1;
+        }
+    } 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;
+        }
     }
-    *slash = '\0';
-    errno = 0;
-    if ( ad_mkdir( path, 0777 ) < 0 ) {
+    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 */
+            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;
+            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;
+
+    LOG(log_maxdebug, logtype_default, "ad_open_hf_ea(\"%s\", adf: 0x%04x, of: 0x%04x)",
+        abspath(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))
+            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",
+                abspath(path));
+            ret = -1;
+            goto error;
+        }
+
+        ad_flush(ad);
     }
-    *slash = '/';
+
+    ad->ad_md->adf_flags = O_RDWR; /* Pretend its rw, in fact for the EA API it is */
+
+    if ((rforklen = sys_lgetxattr(cfrombstr(ad->ad_fullpath), AD_EA_RESO, NULL, 0)) > 0)
+        ad->ad_rlen = rforklen;
+
     return 0;
+
+error:
+    return ret;
+}
+
+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);
+
+    memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
+    ad->ad_rlen = 0;
+
+    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;
+    }
+
+    return ret;
 }
 
-/* ---------------------------------------
- * Put the resource fork where it needs to be:
- * ._name
+/*!
+ * Open EA with resfork, only for AD_VERSION_EA, a nullop otherwise
  */
-char *
-ad_path_osx(const char *path, int adflags _U_)
+static int ad_open_rf(const char *path, int adflags, int oflags, int mode, struct adouble *ad)
 {
-    static char pathbuf[ MAXPATHLEN + 1];
-    char    c, *slash, buf[MAXPATHLEN + 1];
+    int ret = 0;
+
+    if (ad->ad_flags != AD_VERSION_EA)
+        return 0;
 
-    if (!strcmp(path,".")) {
-        /* fixme */
-        getcwd(buf, MAXPATHLEN);
+    LOG(log_debug, logtype_default, "ad_open_rf(\"%s\", adf: 0x%04x, of: 0x%04x)",
+        abspath(path), adflags, oflags);
+
+    if ((ad->ad_rlen = sys_lgetxattr(cfrombstr(ad->ad_fullpath), AD_EA_RESO, NULL, 0)) <= 0) {
+        switch (errno) {
+        case ENOATTR:
+            ad->ad_rlen = 0;
+            break;
+        default:
+            LOG(log_warning, logtype_default, "ad_open_rf(\"%s\"): %s",
+                abspath(path), strerror(errno));
+            ret = -1;
+            goto exit;
+        }
     }
-    else {
-        strlcpy(buf, path, MAXPATHLEN +1);
+
+    /* Round up and allocate buffer */
+    size_t roundup = ((ad->ad_rlen / RFORK_EA_ALLOCSIZE) + 1) * RFORK_EA_ALLOCSIZE;
+    if ((ad->ad_resforkbuf = malloc(roundup)) == NULL) {
+        ret = -1;
+        goto exit;
     }
-    if (NULL != ( slash = strrchr( buf, '/' )) ) {
-        c = *++slash;
-        *slash = '\0';
-        strlcpy( pathbuf, buf, MAXPATHLEN +1);
-        *slash = c;
-    } else {
-        pathbuf[ 0 ] = '\0';
-        slash = buf;
+
+    ad->ad_resforkbufsize = roundup;
+
+    /* Read the EA into the buffer */
+    if (ad->ad_rlen > 0) {
+        if (sys_lgetxattr(cfrombstr(ad->ad_fullpath), AD_EA_RESO, ad->ad_resforkbuf, ad->ad_rlen) == -1) {
+            ret = -1;
+            goto exit;
+        }       
+    }
+
+exit:
+    if (ret != 0) {
+        free(ad->ad_resforkbuf);
+        ad->ad_resforkbuf = NULL;
+        ad->ad_rlen = 0;
+        ad->ad_resforkbufsize = 0;
     }
-    strlcat( pathbuf, "._", MAXPATHLEN  +1);
-    strlcat( pathbuf, slash, MAXPATHLEN +1);
-    return pathbuf;
+
+    return ret;
 }
-/* -------------------- */
-static int ad_mkrf_osx(char *path _U_)
+
+/***********************************************************************************
+ * API functions
+ ********************************************************************************* */
+
+const char *ad_path_ea( const char *path, int adflags _U_)
 {
-    return 0;
+    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)
+const 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 +859,6 @@ use_cur:
     return modebuf;
 }
 
-/* ---------------- */
-static uid_t default_uid = -1;
-
 int ad_setfuid(const uid_t id)
 {
     default_uid = id;
@@ -999,213 +868,152 @@ int ad_setfuid(const uid_t id)
 /* ---------------- */
 uid_t ad_getfuid(void)
 {
-    return default_uid;
-}
-
-/* ----------------
-   return inode of path parent directory
-*/
-int ad_stat(const char *path, struct stat *stbuf)
-{
-    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) {
-        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;
-}
-
-/* --------------------------- */
-static int ad_header_upgrade_none(struct adouble *ad _U_, char *name _U_)
-{
-    return 0;
+    return default_uid;
 }
 
-/* --------------------------- */
-static struct adouble_fops ad_osx = {
-    &ad_path_osx,
-    &ad_mkrf_osx,
-    &ad_rebuild_adouble_header,
-    &ad_check_size,
+/* ----------------
+   stat path parent directory
+*/
+int ad_stat(const char *path, struct stat *stbuf)
+{
+    char *p;
 
-    &ad_header_read,
-    &ad_header_upgrade,
-};
+    p = ad_dir(path);
+    if (!p)
+        return -1;
+    return lstat( p, stbuf );
+}
 
-static struct adouble_fops ad_sfm = {
-    &ad_path_sfm,
-    &ad_mkrf_sfm,
-    &ad_rebuild_sfm_header,
-    &ad_check_size_sfm,
+/* ----------------
+   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;
+}
 
-    &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;
+    memset(ad, 0, sizeof(struct adouble));
+
+    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->ad_flags = flags;
+    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.
-     */
-    memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
-    ad->ad_rlen = 0;
+    ad->ad_inited = AD_INITED;
+}
+
+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_OPENFORKS) {
+        if (!first)
+            strlcat(buf, "|", 64);
+        strlcat(buf, "OF", 64);
+        first = 0;
+    }
+    return buf;
+}
+
+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;
 }
 
 /*!
@@ -1217,310 +1025,101 @@ void ad_init(struct adouble *ad, int flags, int options)
  *      ad_init(&ad, vol->v_adouble, vol->v_ad_options);
  * @endcode
  *
- * @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
+ * Open a files data fork, metadata fork or ressource fork.
+ * For each fork to be opened specify the open flags and mode in case you want to create it
+ * (O_CREAT in open flags). The order in which forks are opened is:
+ * 1. ADFLAGS_DF
+ * 2. ADFLAGS_HF
+ * 3. ADFLAGS_RF
+ * The variable arguments must be passed according to this order.
  *
- * @param oflags  flags passed through to open syscall: \n
- *                O_RDONLY: *** FIXME *** \n
- *                O_RDWR: *** FIXME *** \n
- *                O_CREAT: create fork\n
- *                O_EXCL: fail if exists with O_CREAT
+ * @param ad        (rw) pointer to struct adouble
+ * @param path      (r)  Path to file or directory
+ * @param adflags   (r)  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:    dont upgrade mode from r to rw with adouble:v2 headerfile \n
+ *                       ADFLAGS_OPENFORKS: check for open forks from other processes
  *
- * @param mode    passed to open with O_CREAT
- *
- * @param ad      pointer to struct adouble
- *
- * @returns 0 on success
- *
- * @note It's not possible to open the header file O_RDONLY -- the read
- *       will fail and return an error. this refcounts things now.\n
- *       metadata(ressource)-fork only gets created with O_CREAT.
+ * @returns 0 on success, any other value indicates an error
  */
-int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble  *ad)
+static int vad_open(struct adouble *ad, const char *path, int adflags, va_list args)
 {
-    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;
-
-    if (ad->ad_inited != AD_INITED) {
-        ad->ad_inited = AD_INITED;
-        ad->ad_refcount = 1;
-        ad->ad_open_forks = 0;
-        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_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))
-            ad->ad_open_forks |= ATTRBIT_ROPEN;
-    }
-
-    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;
+    int ret = 0;
+    int oflags;
+    int mode;
+    
+    LOG(log_debug, logtype_default, "ad_open(\"%s\", %s)",
+        abspath(path), adflags2logstr(adflags));
 
-    /* ****************************************** */
+    if (ad->ad_inited != AD_INITED)
+        AFP_PANIC("ad_open: not initialized");
 
-    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;
-            return -1;
+    if (ad->ad_fullpath == NULL) {
+        if ((ad->ad_fullpath = bfromcstr(abspath(path))) == NULL) {
+            ret = -1;
+            goto exit;
         }
-        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 ((adflags & ADFLAGS_DF) && !(ad->ad_adflags & ADFLAGS_DF)) {
+        oflags = va_arg(args, int);
+        if (oflags & O_CREAT)
+            mode = va_arg(args, int);
+        if (ad_open_df(path, adflags, oflags, mode, ad) != 0) {
+            ret = -1;
+            goto exit;
         }
+        ad->ad_adflags |= ADFLAGS_DF;
     }
 
-    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;
+    if ((adflags & ADFLAGS_HF) && !(ad->ad_adflags & ADFLAGS_HF)) {
+        oflags = va_arg(args, int);
+        if (oflags & O_CREAT)
+            mode = va_arg(args, int);
+        if (ad_open_hf(path, adflags, oflags, mode, ad) != 0) {
+            ret = -1;
+            goto exit;
         }
+        ad->ad_adflags |= ADFLAGS_HF;
     }
-    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;
-            return -1;
+    if ((adflags & ADFLAGS_RF) && !(ad->ad_adflags & ADFLAGS_RF)) {
+        oflags = va_arg(args, int);
+        if (oflags & O_CREAT)
+            mode = va_arg(args, int);
+        if (ad_open_rf(path, adflags, oflags, mode, ad) != 0) {
+            ret = -1;
+            goto exit;
         }
+        ad->ad_adflags |= ADFLAGS_RF;
     }
 
-    /* ****************************************** */
-    /* 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))) {
+exit:
+    if (ret != 0) {
+        /* FIXME: ad_close stuff we opened before hitting an error */
+        /* Dont forget ADFLAGS_NOHF !!! */
 
-            ad_close( ad, open_df | ADFLAGS_HF);
-            errno = EACCES;
-            return -1;
+        if (ad->ad_fullpath) {
+            bdestroy(ad->ad_fullpath);
+            ad->ad_fullpath = NULL;
         }
-        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 );
-        }
-    }
+    return ret;
+}
 
-    if ( ad->ad_resource_fork.adf_fd < 0) {
-        int err = errno;
+int ad_open(struct adouble *ad, const char *path, int adflags, ...)
+{
+    int ret;
+    va_list args;
 
-        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 ;
+    va_start(args, adflags);
+    ret = vad_open(ad, path, adflags, args);
+    va_end(args);
+    return ret;
 }
 
 /*!
@@ -1530,29 +1129,18 @@ sfm:
  *
  * @param name  name of file/dir
  * @param flags ADFLAGS_DIR: name is a directory \n
- *              ADFLAGS_CREATE: force creation of header file, but only as user, not as root\n
  *              ADFLAGS_OPENFORKS: test if name is open by another afpd process
  *
  * @param adp   pointer to struct adouble
- *
- * @note caller MUST pass ADFLAGS_DIR for directories. Whether ADFLAGS_CREATE really creates
- *       a adouble file depends on various other volume options, eg. ADVOL_CACHE
  */
 int ad_metadata(const char *name, int flags, struct adouble *adp)
 {
     uid_t uid;
     int   ret, err, dir;
-    int   create = O_RDONLY;
 
     dir = flags & ADFLAGS_DIR;
 
-    /* Check if we shall call ad_open with O_CREAT */
-    if ( (adp->ad_options & ADVOL_CACHE)
-         && ! (adp->ad_options & ADVOL_NOADOUBLE)
-         && (flags & ADFLAGS_CREATE) ) {
-        create = O_CREAT | O_RDWR;
-    }
-    if ((ret = ad_open(name, ADFLAGS_HF | dir, create, 0666, adp)) < 0 && errno == EACCES) {
+    if ((ret = ad_open(adp, name, ADFLAGS_HF | dir, O_RDONLY)) < 0 && errno == EACCES) {
         uid = geteuid();
         if (seteuid(0)) {
             LOG(log_error, logtype_default, "ad_metadata(%s): seteuid failed %s", name, strerror(errno));
@@ -1560,7 +1148,7 @@ int ad_metadata(const char *name, int flags, struct adouble *adp)
             return -1;
         }
         /* we are root open read only */
-        ret = ad_open(name, ADFLAGS_HF|ADFLAGS_RDONLY| dir, O_RDONLY, 0, adp);
+        ret = ad_open(adp, name, ADFLAGS_HF | dir, O_RDONLY);
         err = errno;
         if ( seteuid(uid) < 0) {
             LOG(log_error, logtype_default, "ad_metadata: can't seteuid back");
@@ -1616,95 +1204,23 @@ 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);
 }
 
-int ad_openat(int dirfd,  /* dir fd openat like */
+int ad_openat(struct adouble  *ad,
+              int dirfd,  /* dir fd openat like */
               const char *path,
-              int adflags,
-              int oflags,
-              int mode,
-              struct adouble  *ad)
+              int adflags, ...)
 {
     int ret = 0;
     int cwdfd = -1;
+    va_list args;
 
     if (dirfd != -1) {
         if ((cwdfd = open(".", O_RDONLY) == -1) || (fchdir(dirfd) != 0)) {
@@ -1713,15 +1229,18 @@ int ad_openat(int dirfd,  /* dir fd openat like */
         }
     }
 
-    if (ad_open(path, adflags, oflags, mode, ad) < 0) {
+    va_start(args, adflags);
+
+    if (vad_open(ad, path, adflags, args) < 0) {
         ret = -1;
         goto exit;
     }
 
+    va_end(args);
+
     if (dirfd != -1) {
         if (fchdir(cwdfd) != 0) {
-            LOG(log_error, logtype_afpd, "ad_openat: cant chdir back, exiting");
-            exit(EXITERR_SYS);
+            AFP_PANIC("ad_openat: cant chdir back");
         }
     }
 
diff --git a/libatalk/adouble/ad_private.h b/libatalk/adouble/ad_private.h
deleted file mode 100644 (file)
index 82a11aa..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * $Id: ad_private.h,v 1.6 2008-12-03 18:35:44 didg Exp $
- */
-
-#ifndef LIBATALK_ADOUBLE_AD_PRIVATE_H
-#define LIBATALK_ADOUBLE_AD_PRIVATE_H 1
-
-#include <atalk/adouble.h>
-
-#ifndef MAP_FAILED
-#define MAP_FAILED ((void *) -1)
-#endif /* ! MAP_FAILED */
-
-/* this is so that we can keep lists of fds referencing the same file
- * around. that way, we can honor locks created by the same process
- * with the same file. */
-
-#define adf_lock_init(a) do { \
-       (a)->adf_lockmax = (a)->adf_lockcount = 0; \
-       (a)->adf_excl = 0;(a)->adf_lock = NULL; \
-} while (0)
-
-#define adf_lock_free(a) do { \
-    int i;\
-       if (!(a)->adf_lock) \
-               break; \
-        for (i = 0; i < (a)->adf_lockcount; i++) {\
-            adf_lock_t *lock = (a)->adf_lock + i;\
-            if (--(*lock->refcount) < 1)free(lock->refcount); \
-        }\
-       free((a)->adf_lock); \
-       adf_lock_init(a); \
-} while (0)
-
-#endif /* libatalk/adouble/ad_private.h */
index 17c2361faa99a775fef26c000bfb1ff82a8b2675..877ab574cff326dc3b70750572fa2577d4bec1ab 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: ad_read.c,v 1.10 2010-02-10 14:05:37 franklahm Exp $
- *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
  *
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <atalk/adouble.h>
 #include <string.h>
 #include <sys/param.h>
+#include <errno.h>
+
+#include <atalk/adouble.h>
+#include <atalk/ea.h>
 
 #ifndef MIN
 #define MIN(a,b)    ((a)<(b)?(a):(b))
@@ -77,31 +78,36 @@ ssize_t ad_read( struct adouble *ad, const u_int32_t eid, off_t off, char *buf,
             cc = adf_pread(&ad->ad_data_fork, buf, buflen, off);
         }
     } else {
-        off_t r_off;
-
-        if ( ad_reso_fileno( ad ) == -1 ) {
-            /* resource fork is not open ( cf etc/afp/fork.c) */
-            return 0;
-        }
-        r_off = ad_getentryoff(ad, eid) + off;
-
-        if (( cc = adf_pread( &ad->ad_resource_fork, buf, buflen, r_off )) < 0 ) {
-            return( -1 );
-        }
-        /*
-         * We've just read in bytes from the disk that we read earlier
-         * into ad_data. If we're going to write this buffer out later,
-         * we need to update ad_data.
-         * FIXME : always false?
-         */
-        if (r_off < ad_getentryoff(ad, ADEID_RFORK)) {
-            if ( ad->ad_resource_fork.adf_flags & O_RDWR ) {
-                memcpy(buf, ad->ad_data + r_off,
-                       MIN(sizeof( ad->ad_data ) - r_off, cc));
-            } else {
-                memcpy(ad->ad_data + r_off, buf,
-                       MIN(sizeof( ad->ad_data ) - r_off, cc));
+        if (ad->ad_flags != AD_VERSION_EA) {
+            off_t r_off;
+            if ( ad_reso_fileno( ad ) == -1 )
+                /* resource fork is not open ( cf etc/afp/fork.c) */
+                return 0;
+            r_off = ad_getentryoff(ad, eid) + off;
+            if (( cc = adf_pread( &ad->ad_resource_fork, buf, buflen, r_off )) < 0 )
+                return( -1 );
+            /*
+             * We've just read in bytes from the disk that we read earlier
+             * into ad_data. If we're going to write this buffer out later,
+             * we need to update ad_data.
+             * FIXME : always false?
+             */
+            if (r_off < ad_getentryoff(ad, ADEID_RFORK)) {
+                if ( ad->ad_resource_fork.adf_flags & O_RDWR ) {
+                    memcpy(buf, ad->ad_data + r_off,
+                           MIN(sizeof( ad->ad_data ) - r_off, cc));
+                } else {
+                    memcpy(ad->ad_data + r_off, buf,
+                           MIN(sizeof( ad->ad_data ) - r_off, cc));
+                }
+            }
+        } else { /* AD_VERSION_EA */
+            if ((off + buflen) > ad->ad_rlen) {
+                errno = ERANGE;
+                return -1;
             }
+            memcpy(buf, ad->ad_resforkbuf + off, buflen);
+            cc = buflen;
         }
     }
 
index 2cc9a1f4470f8e75fe7b35b3fd1b6da52f6aec23..2a1f1426aa45b6a5aeb1aa13614c46b3be17e078 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: ad_sendfile.c,v 1.11 2010-01-21 14:14:49 didg Exp $
- *
  * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
  * All rights reserved. See COPYRIGHT.
  *
 #endif /* HAVE_CONFIG_H */
 
 #ifdef WITH_SENDFILE
-
-#include <atalk/adouble.h>
-
 #include <stdio.h>
-
 #include <sys/socket.h>
 #include <sys/uio.h>
-
 #include <errno.h>  
 
+#include <atalk/adouble.h>
 #include <atalk/logger.h>
-#include "ad_private.h"
+
+#include "ad_lock.h"
 
 #if defined(LINUX_BROKEN_SENDFILE_API)
 
index 3031f6390ffa6dc485ba49dc10c55feebd849516..65e3ca2d76005d4e3d6fbc5f91bb2c7427504ab2 100644 (file)
@@ -7,12 +7,15 @@
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <atalk/adouble.h>
-
+#include <stdlib.h>
 #include <string.h>
 #include <sys/param.h>
 #include <errno.h>
 
+#include <atalk/adouble.h>
+#include <atalk/ea.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
 
 #ifndef MIN
 #define MIN(a,b)       ((a)<(b)?(a):(b))
@@ -45,7 +48,7 @@ ssize_t adf_pwrite(struct ad_fd *ad_fd, const void *buf, size_t count, off_t off
 }
 
 /* end is always 0 */
-ssize_t ad_write(struct adouble *ad, const u_int32_t eid, off_t off, const int end, const char *buf, const size_t buflen)
+ssize_t ad_write(struct adouble *ad, uint32_t eid, off_t off, int end, const char *buf, size_t buflen)
 {
     struct stat                st;
     ssize_t            cc;
@@ -57,36 +60,48 @@ ssize_t ad_write(struct adouble *ad, const u_int32_t eid, off_t off, const int e
     }
     
     if ( eid == ADEID_DFORK ) {
-       if ( end ) {
-           if ( fstat( ad_data_fileno(ad), &st ) < 0 ) {
-               return( -1 );
-           }
-           off = st.st_size - off;
-       }
-       cc = adf_pwrite(&ad->ad_data_fork, buf, buflen, off);
-    } else if ( eid == ADEID_RFORK ) {
-        off_t    r_off;
-
-       if ( end ) {
-           if ( fstat( ad_data_fileno(ad), &st ) < 0 ) {
-               return( -1 );
-           }
-           off = st.st_size - off -ad_getentryoff(ad, eid);
-       }
-       r_off = ad_getentryoff(ad, eid) + off;
-       cc = adf_pwrite(&ad->ad_resource_fork, buf, buflen, r_off);
-
-       /* sync up our internal buffer  FIXME always false? */
-       if (r_off < ad_getentryoff(ad, ADEID_RFORK)) {
-           memcpy(ad->ad_data + r_off, buf, MIN(sizeof(ad->ad_data) -r_off, cc));
+        if ( end ) {
+            if ( fstat( ad_data_fileno(ad), &st ) < 0 ) {
+                return( -1 );
+            }
+            off = st.st_size - off;
         }
-        if ( ad->ad_rlen < off + cc ) {
-             ad->ad_rlen = off + cc;
+        cc = adf_pwrite(&ad->ad_data_fork, buf, buflen, off);
+    } else if ( eid == ADEID_RFORK ) {
+        if (ad->ad_flags != AD_VERSION_EA) {
+            off_t    r_off;
+            if ( end ) {
+                if ( fstat( ad_data_fileno(ad), &st ) < 0 )
+                    return( -1 );
+                off = st.st_size - off -ad_getentryoff(ad, eid);
+            }
+            r_off = ad_getentryoff(ad, eid) + off;
+            cc = adf_pwrite(&ad->ad_resource_fork, buf, buflen, r_off);
+
+            /* sync up our internal buffer  FIXME always false? */
+            if (r_off < ad_getentryoff(ad, ADEID_RFORK))
+                memcpy(ad->ad_data + r_off, buf, MIN(sizeof(ad->ad_data) -r_off, cc));
+            if ( ad->ad_rlen < off + cc )
+                ad->ad_rlen = off + cc;
+        } else { /* AD_VERSION_EA */
+            if ((off + buflen) > ad->ad_resforkbufsize) {
+                size_t roundup = (((off + buflen) / RFORK_EA_ALLOCSIZE) + 1) * RFORK_EA_ALLOCSIZE;
+                if ((ad->ad_resforkbuf = realloc(ad->ad_resforkbuf, roundup)) == NULL)
+                    return -1;
+                ad->ad_resforkbufsize = roundup;
+            }
+            memcpy(ad->ad_resforkbuf + off, buf, buflen);
+            if ((off + buflen) > ad->ad_rlen)
+                ad->ad_rlen = off + buflen;
+            
+            if (sys_lsetxattr(cfrombstr(ad->ad_fullpath), AD_EA_RESO, ad->ad_resforkbuf, ad->ad_rlen, 0) == -1)
+                return -1;
+            cc = buflen;
         }
-    }
-    else {
+    } else {
         return -1; /* we don't know how to write if it's not a ressource or data fork */
     }
+
     return( cc );
 }
 
@@ -151,10 +166,10 @@ char            c = 0;
 /* ------------------------ */
 int ad_rtruncate( struct adouble *ad, const off_t size)
 {
-    if ( sys_ftruncate( ad_reso_fileno(ad),
-           size + ad->ad_eid[ ADEID_RFORK ].ade_off ) < 0 ) {
-       return -1;
-    }
+    if (ad->ad_flags != AD_VERSION_EA)
+        if (sys_ftruncate(ad_reso_fileno(ad), size + ad->ad_eid[ ADEID_RFORK ].ade_off ) < 0 )
+            return -1;
+
     ad->ad_rlen = size;    
 
     return 0;
@@ -162,8 +177,8 @@ int ad_rtruncate( struct adouble *ad, const off_t size)
 
 int ad_dtruncate(struct adouble *ad, const off_t size)
 {
-    if (sys_ftruncate(ad_data_fileno(ad), size) < 0) {
-      return -1;
-    }
+    if (sys_ftruncate(ad_data_fileno(ad), size) < 0)
+        return -1;
+
     return 0;
 }
index 97649a7cb2b589f289a6aa7ea0062670b0b65de7..6b7ab4fcdf0b079234ba5f488a70c2b8ea1d60af 100644 (file)
@@ -22,19 +22,19 @@ extern struct _cnid_db *cnid_cdb_open (struct cnid_open_args *args);
 extern void cnid_cdb_close (struct _cnid_db *);
 
 /* cnid_add.c */
-extern cnid_t cnid_cdb_add (struct _cnid_db *, const struct stat *, const cnid_t,
-                           char *, const size_t, cnid_t);
+extern cnid_t cnid_cdb_add (struct _cnid_db *, const struct stat *, cnid_t,
+                            const char *, size_t, cnid_t);
 extern int cnid_cdb_getstamp (struct _cnid_db *, void *, const size_t );
 
 /* cnid_get.c */
-extern cnid_t cnid_cdb_get (struct _cnid_db *, const cnid_t, char *, const size_t); 
+extern cnid_t cnid_cdb_get (struct _cnid_db *, cnid_t, const char *, size_t); 
 extern char *cnid_cdb_resolve (struct _cnid_db *, cnid_t *, void *, size_t ); 
-extern cnid_t cnid_cdb_lookup (struct _cnid_db *, const struct stat *, const cnid_t,
-                              char *, const size_t);
+extern cnid_t cnid_cdb_lookup (struct _cnid_db *, const struct stat *, cnid_t,
+                               const char *, size_t);
 
 /* cnid_update.c */
-extern int cnid_cdb_update (struct _cnid_db *, const cnid_t, const struct stat *,
-                           const cnid_t, char *, size_t);
+extern int cnid_cdb_update (struct _cnid_db *, cnid_t, const struct stat *,
+                            cnid_t, const char *, size_t);
 
 /* cnid_delete.c */
 extern int cnid_cdb_delete (struct _cnid_db *, const cnid_t);
@@ -46,7 +46,7 @@ extern int cnid_cdb_lock   (void *);
 extern int cnid_cdb_unlock (void *);
 
 extern cnid_t cnid_cdb_rebuild_add (struct _cnid_db *, const struct stat *,
-                const cnid_t, char *, const size_t, cnid_t);
+                                    cnid_t, const char *, size_t, cnid_t);
 
 
 #endif /* include/atalk/cnid_cdb.h */
index 418f68cd647cf1fabf777963ef95b71a96537ad5..ff82c52cd6ebcb12be7eb64556c1f57f9cd3ae92 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: cnid_cdb_add.c,v 1.8 2009-11-20 17:22:11 didg Exp $
- *
  * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved. See COPYRIGHT.
  *
@@ -16,9 +14,8 @@
 #ifdef CNID_BACKEND_CDB
 #include "cnid_cdb_private.h"
 
-extern int cnid_cdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
-                const cnid_t did, char *name, const size_t len);
-
+extern int cnid_cdb_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
+                           cnid_t did, const char *name, size_t len);
 
 #define tid    NULL
 
@@ -168,8 +165,7 @@ cleanup:
 
 /* ------------------------ */
 cnid_t cnid_cdb_add(struct _cnid_db *cdb, const struct stat *st,
-                const cnid_t did, char *name, const size_t len,
-                cnid_t hint)
+                    cnid_t did, const char *name, size_t len, cnid_t hint)
 {
     CNID_private *db;
     DBT key, data;
index 5ae4ea02f0ef29fd6de9971f7e19967f83b111fa..d4e090550eab6f85e3de0aa6671f7aa7d6006453 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * $Id: cnid_cdb_get.c,v 1.5 2009-10-29 13:38:16 didg Exp $
- */
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
@@ -10,8 +6,7 @@
 #include "cnid_cdb_private.h"
 
 /* Return CNID for a given did/name. */
-cnid_t cnid_cdb_get(struct _cnid_db *cdb, const cnid_t did, char *name,
-                const size_t len)
+cnid_t cnid_cdb_get(struct _cnid_db *cdb, cnid_t did, const char *name, size_t len)
 {
     char start[CNID_DID_LEN + MAXPATHLEN + 1], *buf;
     CNID_private *db;
index 07de091067fb3b561925e4003f5f2d3831d353b1..7b2f933c5182b4e1c4d4974f5a46c3bd7aa695ac 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * $Id: cnid_cdb_lookup.c,v 1.6 2009-11-20 17:22:11 didg Exp $
- */
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
@@ -14,8 +10,8 @@
 
 /* This returns the CNID corresponding to a particular file.  It will
  * also fix up the various databases if there's a problem. */
-cnid_t cnid_cdb_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
-                   char *name, const size_t len)
+cnid_t cnid_cdb_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did,
+                       const char *name, size_t len)
 {
     unsigned char *buf;
     CNID_private *db;
index 10ecc78d8c34efaf51365820954b1ff5d06c0f6a..056420dad099f1123a6e514f98630055d285fa3a 100644 (file)
 
 static char *old_dbfiles[] = {"cnid.db", NULL};
 
-/* -----------------------
- * bandaid for LanTest performance pb. for now not used, cf. ifdef 0 below
-*/
-static int my_yield(void)
-{
-    struct timeval t;
-    int ret;
-
-    t.tv_sec = 0;
-    t.tv_usec = 1000;
-    ret = select(0, NULL, NULL, NULL, &t);
-    return 0;
-}
-
 /* --------------- */
 static int didname(DB *dbp _U_, const DBT *pkey _U_, const DBT *pdata, DBT *skey)
 {
@@ -368,7 +354,6 @@ struct _cnid_db *cnid_cdb_open(struct cnid_open_args *args)
         }
     }
 
-    db_env_set_func_yield(my_yield);
     return cdb;
 
   fail_appinit:
index 351f31536073982a4b3f08be5e1b40f61fec8f21..be2db1023692be7e7d966b76e23d1773b37ee1a0 100644 (file)
@@ -73,10 +73,8 @@ cleanup:
     return CNID_INVALID;
 }
 
-/* ------------------------ */
 cnid_t cnid_cdb_rebuild_add(struct _cnid_db *cdb, const struct stat *st,
-                const cnid_t did, char *name, const size_t len, 
-               cnid_t hint)
+                            cnid_t did, const char *name, size_t len, cnid_t hint)
 {
     CNID_private *db;
     DBT key, data;
index f1a4a30dc48b24f6bedbbca48d7d034f81d57615..f7676c840054516c10be062dae3e874719b7e23e 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * $Id: cnid_cdb_update.c,v 1.4 2009-11-20 17:22:11 didg Exp $
- */
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
@@ -14,9 +10,8 @@
 /* cnid_update: takes the given cnid and updates the metadata.  To
  * handle the did/name data, there are a bunch of functions to get
  * and set the various fields. */
-int cnid_cdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
-                const cnid_t did, char *name, const size_t len
-                /*, const char *info, const int infolen*/)
+int cnid_cdb_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
+                    cnid_t did, const char *name, size_t len)
 {
     unsigned char *buf;
     CNID_private *db;
index 990248e45e439a22bc4de87377ae8fbe7e1e95f7..ab5a20f267af0850e979cbf5c10dc9afc66a1813 100644 (file)
@@ -273,7 +273,7 @@ static int send_packet(CNID_private *db, struct cnid_dbd_rqst *rqst)
     vecs = 1;
 
     if (rqst->namelen) {
-        iov[1].iov_base = rqst->name;
+        iov[1].iov_base = (char *)rqst->name;
         iov[1].iov_len  = rqst->namelen;
         towrite += rqst->namelen;
         vecs++;
@@ -538,8 +538,7 @@ void cnid_dbd_close(struct _cnid_db *cdb)
 
 /* ---------------------- */
 cnid_t cnid_dbd_add(struct _cnid_db *cdb, const struct stat *st,
-                    const cnid_t did, char *name, const size_t len,
-                    cnid_t hint)
+                    cnid_t did, const char *name, size_t len, cnid_t hint)
 {
     CNID_private *db;
     struct cnid_dbd_rqst rqst;
@@ -603,7 +602,7 @@ cnid_t cnid_dbd_add(struct _cnid_db *cdb, const struct stat *st,
 }
 
 /* ---------------------- */
-cnid_t cnid_dbd_get(struct _cnid_db *cdb, const cnid_t did, char *name, const size_t len)
+cnid_t cnid_dbd_get(struct _cnid_db *cdb, cnid_t did, const char *name, size_t len)
 {
     CNID_private *db;
     struct cnid_dbd_rqst rqst;
@@ -729,8 +728,8 @@ int cnid_dbd_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len)
 }
 
 /* ---------------------- */
-cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
-                       char *name, const size_t len)
+cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did,
+                       const char *name, size_t len)
 {
     CNID_private *db;
     struct cnid_dbd_rqst rqst;
@@ -791,7 +790,7 @@ cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t
 }
 
 /* ---------------------- */
-int cnid_dbd_find(struct _cnid_db *cdb, char *name, size_t namelen, void *buffer, size_t buflen)
+int cnid_dbd_find(struct _cnid_db *cdb, const char *name, size_t namelen, void *buffer, size_t buflen)
 {
     CNID_private *db;
     struct cnid_dbd_rqst rqst;
@@ -846,8 +845,8 @@ int cnid_dbd_find(struct _cnid_db *cdb, char *name, size_t namelen, void *buffer
 }
 
 /* ---------------------- */
-int cnid_dbd_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
-                    const cnid_t did, char *name, const size_t len)
+int cnid_dbd_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
+                    cnid_t did, const char *name, size_t len)
 {
     CNID_private *db;
     struct cnid_dbd_rqst rqst;
@@ -901,8 +900,7 @@ int cnid_dbd_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st
 
 /* ---------------------- */
 cnid_t cnid_dbd_rebuild_add(struct _cnid_db *cdb, const struct stat *st,
-                            const cnid_t did, char *name, const size_t len,
-                            cnid_t hint)
+                            cnid_t did, const char *name, size_t len, cnid_t hint)
 {
     CNID_private *db;
     struct cnid_dbd_rqst rqst;
index 1f645908358b442633beae7e730e9789be690975..be8659d6cdfdac596019d661d8a73e3cd3549460 100644 (file)
 extern struct _cnid_module cnid_dbd_module;
 extern struct _cnid_db *cnid_dbd_open (struct cnid_open_args *args);
 extern void   cnid_dbd_close      (struct _cnid_db *);
-extern cnid_t cnid_dbd_add        (struct _cnid_db *, const struct stat *, const cnid_t,
-                                   char *, const size_t, cnid_t);
-extern cnid_t cnid_dbd_get        (struct _cnid_db *, const cnid_t, char *, const size_t); 
+extern cnid_t cnid_dbd_add        (struct _cnid_db *, const struct stat *, cnid_t,
+                                   const char *, size_t, cnid_t);
+extern cnid_t cnid_dbd_get        (struct _cnid_db *, cnid_t, const char *, size_t); 
 extern char  *cnid_dbd_resolve    (struct _cnid_db *, cnid_t *, void *, size_t ); 
 extern int    cnid_dbd_getstamp   (struct _cnid_db *, void *, const size_t ); 
-extern cnid_t cnid_dbd_lookup     (struct _cnid_db *, const struct stat *, const cnid_t,
-                                   char *, const size_t);
-extern int    cnid_dbd_find       (struct _cnid_db *cdb, char *name, size_t namelen,
+extern cnid_t cnid_dbd_lookup     (struct _cnid_db *, const struct stat *, cnid_t,
+                                   const char *, size_t);
+extern int    cnid_dbd_find       (struct _cnid_db *cdb, const char *name, size_t namelen,
                                    void *buffer, size_t buflen);
-extern int    cnid_dbd_update     (struct _cnid_db *, const cnid_t, const struct stat *,
-                                   const cnid_t, char *, size_t);
+extern int    cnid_dbd_update     (struct _cnid_db *, cnid_t, const struct stat *,
+                                   cnid_t, const char *, size_t);
 extern int    cnid_dbd_delete     (struct _cnid_db *, const cnid_t);
 extern cnid_t cnid_dbd_rebuild_add(struct _cnid_db *, const struct stat *,
-                                   const cnid_t, char *, const size_t, cnid_t);
+                                   cnid_t, const char *, size_t, cnid_t);
 
 /* FIXME: These functions could be static in cnid_dbd.c */
 
index 5502fb60f94c49836b9de1cd62005ebdeec7f841..1ed78b4628e6fab46083488af4f7697c64d10e0e 100644 (file)
@@ -23,7 +23,7 @@
 
 /* ------------------------ */
 cnid_t cnid_last_add(struct _cnid_db *cdb, const struct stat *st,
-                     const cnid_t did _U_, char *name _U_, const size_t len _U_, cnid_t hint _U_)
+                     cnid_t did _U_, const char *name _U_, size_t len _U_, cnid_t hint _U_)
 {
 
     /* FIXME: it relies on fact, that this is never called twice for the same file/dir. */
@@ -86,9 +86,8 @@ int cnid_last_delete(struct _cnid_db *cdb _U_, const cnid_t id _U_)
 }
 
 
-
 /* Return CNID for a given did/name. */
-cnid_t cnid_last_get(struct _cnid_db *cdb _U_, const cnid_t did _U_, char *name _U_, const size_t len _U_)
+cnid_t cnid_last_get(struct _cnid_db *cdb _U_, cnid_t did _U_, const char *name _U_, size_t len _U_)
 {
     /* FIXME: it relies on fact, that this is never called twice for the same file/dir. */
     /* Propably we should look through DID tree. */
@@ -96,10 +95,9 @@ cnid_t cnid_last_get(struct _cnid_db *cdb _U_, const cnid_t did _U_, char *name
 }
 
 
-
 /* */
-cnid_t cnid_last_lookup(struct _cnid_db *cdb _U_, const struct stat *st _U_, const cnid_t did _U_, 
-    char *name _U_, const size_t len _U_)
+cnid_t cnid_last_lookup(struct _cnid_db *cdb _U_, const struct stat *st _U_, cnid_t did _U_, 
+                        const char *name _U_, size_t len _U_)
 {
     /* FIXME: this function doesn't work in [last] scheme ! */
     /* Should be never called or CNID should be somewhat refactored again. */
@@ -175,8 +173,8 @@ char *cnid_last_resolve(struct _cnid_db *cdb _U_, cnid_t * id _U_, void *buffer
 }
 
 
-int cnid_last_update(struct _cnid_db *cdb _U_, const cnid_t id _U_, const struct stat *st _U_,
-                     const cnid_t did  _U_, char *name  _U_, const size_t len _U_)
+int cnid_last_update(struct _cnid_db *cdb _U_, cnid_t id _U_, const struct stat *st _U_,
+                     cnid_t did  _U_, const char *name  _U_, size_t len _U_)
 {
     return 0;
 }
index fdcf32a5cc524fc74e4abba68670d4ef792b20a4..9f944dda51f82f679a37a354e1a3f96bdbf1ebfb 100644 (file)
@@ -22,13 +22,13 @@ struct _cnid_last_private {
 extern struct _cnid_module cnid_last_module;
 extern struct _cnid_db *cnid_last_open (struct cnid_open_args *args);
 extern void cnid_last_close (struct _cnid_db *);
-extern cnid_t cnid_last_add (struct _cnid_db *, const struct stat *, const cnid_t,
-                                 char *, const size_t, cnid_t);
-extern cnid_t cnid_last_get (struct _cnid_db *, const cnid_t, char *, const size_t);
+extern cnid_t cnid_last_add (struct _cnid_db *, const struct stat *, cnid_t,
+                             const char *, size_t, cnid_t);
+extern cnid_t cnid_last_get (struct _cnid_db *, cnid_t, const char *, size_t);
 extern char *cnid_last_resolve (struct _cnid_db *, cnid_t *, void *, size_t);
-extern cnid_t cnid_last_lookup (struct _cnid_db *, const struct stat *, const cnid_t, char *, const size_t);
-extern int cnid_last_update (struct _cnid_db *, const cnid_t, const struct stat *,
-                                 const cnid_t, char *, size_t);
-extern int cnid_last_delete (struct _cnid_db *, const cnid_t);
+extern cnid_t cnid_last_lookup (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t);
+extern int cnid_last_update (struct _cnid_db *, cnid_t, const struct stat *,
+                             cnid_t, const char *, size_t);
+extern int cnid_last_delete (struct _cnid_db *, cnid_t);
 
 #endif /* include/atalk/cnid_last.h */
index 1f7a08e6336dfb2ad6274dbac77c165c0e9fd11d..0bf978a587501a382b968fada89a9d640a8e0288 100644 (file)
@@ -53,17 +53,17 @@ extern struct _cnid_db *cnid_tdb_open (struct cnid_open_args *args);
 extern void cnid_tdb_close (struct _cnid_db *);
 
 /* cnid_add.c */
-extern cnid_t cnid_tdb_add (struct _cnid_db *, const struct stat *, const cnid_t,
-                                 char *, const size_t, cnid_t);
+extern cnid_t cnid_tdb_add (struct _cnid_db *, const struct stat *, cnid_t,
+                            const char *, size_t, cnid_t);
 
 /* cnid_get.c */
-extern cnid_t cnid_tdb_get (struct _cnid_db *, const cnid_t, char *, const size_t);
+extern cnid_t cnid_tdb_get (struct _cnid_db *, cnid_t, const char *, size_t);
 extern char *cnid_tdb_resolve (struct _cnid_db *, cnid_t *, void *, size_t);
-extern cnid_t cnid_tdb_lookup (struct _cnid_db *, const struct stat *, const cnid_t, char *, const size_t);
+extern cnid_t cnid_tdb_lookup (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t);
 
 /* cnid_update.c */
-extern int cnid_tdb_update (struct _cnid_db *, const cnid_t, const struct stat *,
-                                 const cnid_t, char *, size_t);
+extern int cnid_tdb_update (struct _cnid_db *, cnid_t, const struct stat *,
+                            cnid_t, const char *, size_t);
 
 /* cnid_delete.c */
 extern int cnid_tdb_delete (struct _cnid_db *, const cnid_t);
index 5758300c2e528c6b8a513b086fb8a4fb4a43e1e9..e49fdd30cc6ddfa52ce967f99ad014d662f63b84 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: cnid_tdb_add.c,v 1.4 2009-11-20 17:37:14 didg Exp $
- *
  * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved. See COPYRIGHT.
  *
@@ -154,7 +152,7 @@ cleanup:
 
 /* ------------------------ */
 cnid_t cnid_tdb_add(struct _cnid_db *cdb, const struct stat *st,
-                     const cnid_t did, char *name, const size_t len, cnid_t hint)
+                    cnid_t did, const char *name, size_t len, cnid_t hint)
 {
     const struct stat *lstp;
     cnid_t id;
index 019eea5287567c7a024f2f038f0a7c6f0f4de360..8321d04e868eb20469c061bd08c0057c7dacc7ae 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * $Id: cnid_tdb_get.c,v 1.4 2009-11-20 17:37:14 didg Exp $
- */
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -11,7 +7,7 @@
 #include "cnid_tdb.h"
 
 /* Return CNID for a given did/name. */
-cnid_t cnid_tdb_get(struct _cnid_db *cdb, const cnid_t did, char *name, const size_t len)
+cnid_t cnid_tdb_get(struct _cnid_db *cdb, cnid_t did, const char *name, size_t len)
 {
     char start[CNID_DID_LEN + MAXPATHLEN + 1], *buf;
     struct _cnid_tdb_private *db;
index ba47e36837f197c42f6b302f0a22ed78ca68e77c..457362bf1b5fc536ebceb445b8e524a3df44fe55 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * $Id: cnid_tdb_lookup.c,v 1.6 2009-11-21 11:12:49 didg Exp $
- */
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -11,7 +7,7 @@
 #include "cnid_tdb.h"
 #include <atalk/logger.h>
 
-cnid_t cnid_tdb_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, char *name, const size_t len)
+cnid_t cnid_tdb_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did, const char *name, size_t len)
 {
     char *buf;
     struct _cnid_tdb_private *db;
index d658b94ae25f785399da7175bd3cc67a5f206d69..4c2e050b10e348181db7f07a86b66789e0755f5d 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: cnid_tdb_open.c,v 1.8 2010-03-31 09:47:32 franklahm Exp $
- *
  * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
  * All Rights Reserved. See COPYRIGHT.
  *
index 8c4d35e379dd535b7085719df8c6eb783c719d1e..d367334e06126c8f903fe8bea20d1a0d7efea0b1 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * $Id: cnid_tdb_update.c,v 1.6 2009-11-21 11:12:49 didg Exp $
- */
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -11,9 +7,8 @@
 #include "cnid_tdb.h"
 #include <atalk/logger.h>
 
-int cnid_tdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
-                     const cnid_t did, char *name, const size_t len
-                     /*, const char *info, const int infolen */ )
+int cnid_tdb_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
+                    cnid_t did, const char *name, size_t len)
 {
     struct _cnid_tdb_private *db;
     TDB_DATA key, data, altdata;
index ebe54b21a8b0d2b52213b3a352fe495af37a319a..515681d38daf59c11643e094a4136b523599bb13 100644 (file)
@@ -3,12 +3,6 @@
 noinst_LTLIBRARIES = libcompat.la
 
 libcompat_la_SOURCES = \
-       mktemp.c        \
        getusershell.c  \
-       strcasecmp.c    \
-       strstr.c        \
-       strdup.c        \
-       inet_aton.c     \
        rquota_xdr.c    \
-       pselect.c       \
-       snprintf.c
+       pselect.c
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..032c045
--- /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)
+{
+    const 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(&ad, dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666)) != 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(&ad, dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666)) != 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..014a7482905e810ec2b19b7b0716a12bcc0e5d87 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
  **********************************************************************************/
@@ -215,6 +195,8 @@ int sys_get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
  *
  * Copies names of all EAs of uname as consecutive C strings into rbuf.
  * Increments *rbuflen accordingly.
+ * We hide the adouble:ea extended attributes here, but we currently
+ * allow reading, writing and deleteting them.
  */
 int sys_list_eas(VFS_FUNC_ARGS_EA_LIST)
 {
@@ -253,26 +235,27 @@ int sys_list_eas(VFS_FUNC_ARGS_EA_LIST)
     ptr = buf;
     while (ret > 0)  {
         len = strlen(ptr);
+        if (NOT_NETATALK_EA(ptr)) {
+            /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
+            if ( 0 >= ( nlen = convert_string(vol->v_volcharset, CH_UTF8_MAC, ptr, len, attrnamebuf + attrbuflen, 256)) ) {
+                ret = AFPERR_MISC;
+                goto exit;
+            }
 
-        /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
-        if ( 0 >= ( nlen = convert_string(vol->v_volcharset, CH_UTF8_MAC, ptr, len, attrnamebuf + attrbuflen, 256)) ) {
-            ret = AFPERR_MISC;
-            goto exit;
-        }
-
-        LOG(log_debug7, logtype_afpd, "sys_list_extattr(%s): attribute: %s", uname, ptr);
+            LOG(log_debug7, logtype_afpd, "sys_list_extattr(%s): attribute: %s", uname, ptr);
 
-        attrbuflen += nlen + 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, "sys_list_extattr(%s): running out of buffer for EA names", uname);
-            ret = AFPERR_MISC;
-            goto exit;
+            attrbuflen += nlen + 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, "sys_list_extattr(%s): running out of buffer for EA names", uname);
+                ret = AFPERR_MISC;
+                goto exit;
+            }
         }
-        ret -= len +1;
-        ptr += len +1;
+        ret -= len + 1;
+        ptr += len + 1;
     }
 
     ret = AFP_OK;
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..15492a5d62a1edea8390423ae1167e2bb5c709e8 100644 (file)
@@ -114,7 +114,7 @@ static int validupath_adouble(VFS_FUNC_ARGS_VALIDUPATH)
 static int RF_chown_adouble(VFS_FUNC_ARGS_CHOWN)
 {
     struct stat st;
-    char        *ad_p;
+    const char *ad_p;
 
     ad_p = vol->ad_path(path, ADFLAGS_HF );
 
@@ -173,7 +173,7 @@ static int RF_setfilmode_adouble(VFS_FUNC_ARGS_SETFILEMODE)
 /* ----------------- */
 static int RF_setdirunixmode_adouble(VFS_FUNC_ARGS_SETDIRUNIXMODE)
 {
-    char *adouble = vol->ad_path(name, ADFLAGS_DIR );
+    const char *adouble = vol->ad_path(name, ADFLAGS_DIR );
     int  dropbox = vol->v_flags;
 
     if (dir_rx_set(mode)) {
@@ -214,8 +214,8 @@ static int RF_setdirmode_adouble(VFS_FUNC_ARGS_SETDIRMODE)
 {
     int   dropbox = vol->v_flags;
     mode_t hf_mode = ad_hf_mode(mode);
-    char  *adouble = vol->ad_path(name, ADFLAGS_DIR );
-    char  *adouble_p = ad_dir(adouble);
+    const char  *adouble = vol->ad_path(name, ADFLAGS_DIR );
+    const char  *adouble_p = ad_dir(adouble);
 
     if (dir_rx_set(mode)) {
         if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox, vol->v_umask) < 0) 
@@ -308,7 +308,7 @@ static int RF_renamefile_adouble(VFS_FUNC_ARGS_RENAMEFILE)
              * 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)) {
+            if (ad_open(&ad, dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666) == 0) {
                ad_close(&ad, ADFLAGS_HF);
                if (!unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) ) 
                    err = 0;
@@ -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 */