]> arthur.barton.de Git - netatalk.git/commitdiff
Implement VFS chaining, EA VFS rm/mv
authorfranklahm <franklahm>
Wed, 14 Oct 2009 15:04:00 +0000 (15:04 +0000)
committerfranklahm <franklahm>
Wed, 14 Oct 2009 15:04:00 +0000 (15:04 +0000)
13 files changed:
contrib/shell_utils/.cvsignore
etc/afpd/directory.c
etc/afpd/enumerate.c
etc/afpd/extattrs.c
etc/afpd/file.c
etc/afpd/filedir.c
etc/afpd/unix.c
include/atalk/Makefile.am
include/atalk/acl.h [new file with mode: 0644]
include/atalk/ea.h
include/atalk/vfs.h
libatalk/vfs/ea.c
libatalk/vfs/vfs.c

index 0d52d6241bcf6532d3737e3f9a66037bc3937592..eea210568b5d3029bdfecb59178d0a07bcb7fb82 100644 (file)
@@ -1,6 +1,7 @@
 Makefile
 Makefile.in
 afpd-mtab.pl
+apple_cleanup
 apple_cp
 apple_mv
 apple_rm
index 148ec2179782e386d086aac4b763f909d9c0f6d3..619129e83e4ed20ea7a160b4c2e81459ef56ce92 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.c,v 1.106 2009-10-13 22:55:36 didg Exp $
+ * $Id: directory.c,v 1.107 2009-10-14 15:04:00 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -955,8 +955,8 @@ struct dir *
         return NULL;
     }
     if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, path->m_name, strlen(path->m_name), &cdir->d_m_name_ucs2)) {
-       LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
-       cdir->d_m_name_ucs2 = NULL;
+        LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
+        cdir->d_m_name_ucs2 = NULL;
     }
 
     cdir->d_did = id;
@@ -2430,7 +2430,7 @@ int renamedir(const struct vol *vol, char *src, char *dst,
         }
     }
 
-    vol->vfs->rf_renamedir(vol, src, dst);
+    vol->vfs->vfs_renamedir(vol, src, dst);
 
     len = strlen( newname );
     /* rename() succeeded so we need to update our tree even if we can't open
@@ -2518,7 +2518,7 @@ int deletecurdir(const struct vol *vol)
             return  AFPERR_OLOCK;
         }
     }
-    err = vol->vfs->rf_deletecurdir(vol);
+    err = vol->vfs->vfs_deletecurdir(vol);
     if (err) {
         return err;
     }
index e029a877e3db609d50fe44ebe35c3e4ae94c4ec3..a0453d94809f9209928661ca9c0589437db5af76 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: enumerate.c,v 1.45 2009-10-13 22:55:36 didg Exp $
+ * $Id: enumerate.c,v 1.46 2009-10-14 15:04:00 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -97,16 +97,16 @@ static int enumerate_loop(struct dirent *de, char *mname _U_, void *data)
 */
 char *check_dirent(const struct vol *vol, char *name)
 {
-
     if (!strcmp(name, "..") || !strcmp(name, "."))
         return NULL;
 
-    if (!vol->vfs->validupath(vol, name))
+    if (!vol->vfs->vfs_validupath(vol, name))
         return NULL;
 
     /* check for vetoed filenames */
     if (veto_file(vol->v_veto, name))
         return NULL;
+
 #if 0
     char *m_name = NULL;
 
index 7748480aa3686801a2c4858453ba5cfd8c41161d..2900be3d2b7ab91da36d846fbb28069b685ef198 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  $Id: extattrs.c,v 1.4 2009-10-02 09:32:40 franklahm Exp $
+  $Id: extattrs.c,v 1.5 2009-10-14 15:04:00 franklahm Exp $
   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
@@ -183,7 +183,7 @@ int afp_listextattr(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf, int *r
             attrbuflen += strlen(ea_resourcefork) + 1;
         }
 
-        ret = vol->vfs->list_eas(vol, attrnamebuf, &attrbuflen, uname, oflag);
+        ret = vol->vfs->vfs_ea_list(vol, attrnamebuf, &attrbuflen, uname, oflag);
 
         switch (ret) {
         case AFPERR_BADTYPE:
@@ -319,9 +319,9 @@ int afp_getextattr(AFPObj *obj _U_, char *ibuf, int ibuflen _U_, char *rbuf, int
       if its non 0 we must return the attribute.
     */
     if (maxreply == 0)
-        ret = vol->vfs->get_easize(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname);
+        ret = vol->vfs->vfs_ea_getsize(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname);
     else
-        ret = vol->vfs->get_eacontent(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, maxreply);
+        ret = vol->vfs->vfs_ea_getcontent(vol, rbuf, rbuflen, s_path->u_name, oflag, attruname, maxreply);
 
     return ret;
 }
@@ -409,7 +409,7 @@ int afp_setextattr(AFPObj *obj _U_, char *ibuf, int ibuflen _U_, char *rbuf, int
 
     LOG(log_debug, logtype_afpd, "afp_setextattr(%s): EA: %s, size: %u", s_path->u_name, attrmname, attrsize);
 
-    ret = vol->vfs->set_ea(vol, s_path->u_name, attruname, ibuf, attrsize, oflag);
+    ret = vol->vfs->vfs_ea_set(vol, s_path->u_name, attruname, ibuf, attrsize, oflag);
 
     return ret;
 }
@@ -481,7 +481,7 @@ int afp_remextattr(AFPObj *obj _U_, char *ibuf, int ibuflen _U_, char *rbuf, int
 
     LOG(log_debug, logtype_afpd, "afp_remextattr(%s): EA: %s", s_path->u_name, attrmname);
 
-    ret = vol->vfs->remove_ea(vol, s_path->u_name, attruname, oflag);
+    ret = vol->vfs->vfs_ea_remove(vol, s_path->u_name, attruname, oflag);
 
     return ret;
 }
index a7498983c6d06ef60e75619067a3f45447e86832..91284a57d52dad8d8231b16ca9d42c3e8bb1204b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.c,v 1.112 2009-10-13 22:55:36 didg Exp $
+ * $Id: file.c,v 1.113 2009-10-14 15:04:00 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -1037,7 +1037,7 @@ int renamefile(const struct vol *vol, char *src, char *dst, char *newname, struc
         }
     }
 
-    if (vol->vfs->rf_renamefile(vol, src, dst) < 0 ) {
+    if (vol->vfs->vfs_renamefile(vol, src, dst) < 0 ) {
         int err;
         
         err = errno;        
@@ -1574,7 +1574,7 @@ int deletefile(const struct vol *vol, char *file, int checkAttrib)
     if (adp && ad_tmplock( &ad, ADEID_DFORK, ADLOCK_WR, 0, 0, 0 ) < 0) {
         err = AFPERR_BUSY;
     }
-    else if (!(err = vol->vfs->rf_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
+    else if (!(err = vol->vfs->vfs_deletefile(vol, file)) && !(err = netatalk_unlink( file )) ) {
         cnid_t id;
         if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) 
         {
index ddc2fad64712a327a94ba7c77dc04a6162787d53..2e26e51951897dc85fae6e84ce48770960d1e379 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: filedir.c,v 1.56 2009-10-13 22:55:37 didg Exp $
+ * $Id: filedir.c,v 1.57 2009-10-14 15:04:01 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -311,7 +311,7 @@ int check_name(const struct vol *vol, char *name)
     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(name, '/'))
         return AFPERR_PARAM;
 
-    if (!vol->vfs->validupath(vol, name)) {
+    if (!vol->vfs->vfs_validupath(vol, name)) {
         LOG(log_info, logtype_afpd, "check_name: illegal name: '%s'", name);
         return AFPERR_EXIST;
     }
@@ -731,7 +731,7 @@ int afp_moveandrename(AFPObj *obj, char *ibuf, int ibuflen  _U_, char *rbuf _U_,
                 int  admode = ad_mode("", 0777) | vol->v_fperm;
 
                 setfilmode(upath, admode, NULL, vol->v_umask);
-                vol->vfs->rf_setfilmode(vol, upath, admode, NULL);
+                vol->vfs->vfs_setfilmode(vol, upath, admode, NULL);
             }
         setvoltime(obj, vol );
     }
index 48ece6058f38aca072992575cf34d97f13b7a0cd..5ab23eeafe453de2a3b1865b7bb9c628f6f699e1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: unix.c,v 1.54 2009-10-13 22:55:37 didg Exp $
+ * $Id: unix.c,v 1.55 2009-10-14 15:04:01 franklahm Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -330,7 +330,7 @@ int setfilunixmode (const struct vol *vol, struct path* path, mode_t mode)
     if (setfilmode( path->u_name, mode, &path->st, vol->v_umask) < 0)
         return -1;
     /* we need to set write perm if read set for resource fork */
-    return vol->vfs->rf_setfilmode(vol, path->u_name, mode, &path->st);
+    return vol->vfs->vfs_setfilmode(vol, path->u_name, mode, &path->st);
 }
 
 
@@ -346,7 +346,7 @@ int setdirunixmode(const struct vol *vol, const char *name, mode_t mode)
        if ( stickydirmode(name, DIRBITS | mode, dropbox, vol->v_umask) < 0 )
                return -1;
     }
-    if (vol->vfs->rf_setdirunixmode(vol, name, mode, NULL) < 0 && !vol_noadouble(vol)) {
+    if (vol->vfs->vfs_setdirunixmode(vol, name, mode, NULL) < 0 && !vol_noadouble(vol)) {
         return  -1 ;
     }
     if (!dir_rx_set(mode)) {
@@ -401,7 +401,7 @@ int setdirmode(const struct vol *vol, const char *name, mode_t mode)
     }
     closedir( dir );
     
-    if (vol->vfs->rf_setdirmode(vol, name, mode, NULL) < 0 && !vol_noadouble(vol)) {
+    if (vol->vfs->vfs_setdirmode(vol, name, mode, NULL) < 0 && !vol_noadouble(vol)) {
         return  -1 ;
     }
 
@@ -492,7 +492,7 @@ int setfilowner(const struct vol *vol, const uid_t uid, const gid_t gid, struct
        return -1;
     }
 
-    if (vol->vfs->rf_chown(vol, path->u_name, uid, gid ) < 0 && errno != EPERM) {
+    if (vol->vfs->vfs_chown(vol, path->u_name, uid, gid ) < 0 && errno != EPERM) {
         LOG(log_debug, logtype_afpd, "setfilowner: rf_chown %d/%d %s: %s",
             uid, gid, path->u_name, strerror(errno) );
         return -1;
@@ -535,7 +535,7 @@ int setdirowner(const struct vol *vol, const char *name, const uid_t uid, const
     }
     closedir( dir );
 
-    if (vol->vfs->rf_setdirowner(vol, name, uid, gid) < 0) {
+    if (vol->vfs->vfs_setdirowner(vol, name, uid, gid) < 0) {
         return -1;
     }
     
index f7af5585791b9c6854599c9bfd59ea5b5d1c4b4d..40d4121bd31114173bd16851d122b9e0453e8ec1 100644 (file)
@@ -6,6 +6,6 @@ atalkinclude_HEADERS = \
        cnid.h compat.h ddp.h dsi.h ldapconfig.h list.h logger.h \
        nbp.h netddp.h pap.h paths.h rtmp.h server_child.h \
        server_ipc.h tdb.h uam.h unicode.h util.h uuid.h volinfo.h \
-       zip.h ea.h
+       zip.h ea.h acl.h
 
 noinst_HEADERS = cnid_dbd_private.h
diff --git a/include/atalk/acl.h b/include/atalk/acl.h
new file mode 100644 (file)
index 0000000..edb3915
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+   $Id: acl.h,v 1.1 2009-10-14 15:04:01 franklahm Exp $
+   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+#ifndef ATALK_ACL_H
+#define ATALK_ACL_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_NFSv4_ACLS
+#include <sys/acl.h>
+#endif  /* HAVE_NFSv4_ACLS */
+
+/* Solaris NFSv4 ACL stuff */
+#ifdef HAVE_NFSv4_ACLS
+extern int get_nfsv4_acl(const char *name, ace_t **retAces);
+extern int remove_acl(const char *name);
+#endif /* HAVE_NFSv4_ACLS */
+
+
+#endif  /* ATALK_ACL_H */
index 3509745c57ea5cdfae393d7a44a6efc65fe7f180..febf91fa5504acd510ff9bebec765c0d8d15beb4 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   $Id: ea.h,v 1.1 2009-10-02 09:32:40 franklahm Exp $
+   $Id: ea.h,v 1.2 2009-10-14 15:04:01 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
 
+#ifdef HAVE_NFSv4_ACLS
+#include <sys/acl.h>
+#endif
+
+#include <atalk/vfs.h>
+
 /*
  * This seems to be the current limit fo HFS+, we arbitrarily force that
  *  which also safes us from buffer overflows
@@ -45,7 +51,7 @@ enum {
     kXAttrReplace = 0x4
 };
 
-
+#define EA_INITED   0xea494e54  /* ea"INT", for interfacing ea_open w. ea_close */
 #define EA_MAGIC    0x61644541 /* "adEA" */
 #define EA_VERSION1 0x01
 #define EA_VERSION  EA_VERSION1
@@ -81,6 +87,7 @@ struct ea_entry {
 
 /* We read the on-disk data into *ea_data and parse it into this*/
 struct ea {
+    uint32_t             ea_inited;       /* needed for interfacing ea_open w. ea_close */
     const struct vol     *vol;            /* vol handle, ea_close needs it */
     char                 *filename;       /* name of file, needed by ea_close too */
     unsigned int         ea_count;        /* number of EAs in ea_entries array */
@@ -107,4 +114,25 @@ struct ea_ondisk {
 };
 #endif /* 0 */
 
+/* VFS inderected funcs ... : */
+
+/* Default adouble EAs */
+extern int get_easize(VFS_FUNC_ARGS_EA_GETSIZE);
+extern int get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT);
+extern int list_eas(VFS_FUNC_ARGS_EA_LIST);
+extern int set_ea(VFS_FUNC_ARGS_EA_SET);
+extern int remove_ea(VFS_FUNC_ARGS_EA_REMOVE);
+/* ... EA VFS funcs that deal with file/dir cp/mv/rm */
+extern int ea_deletefile(VFS_FUNC_ARGS_DELETEFILE);
+extern int ea_renamefile(VFS_FUNC_ARGS_RENAMEFILE);
+
+/* Solaris native EAs */
+#ifdef HAVE_SOLARIS_EAS
+extern int sol_get_easize(VFS_FUNC_ARGS_EA_GETSIZE);
+extern int sol_get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT);
+extern int sol_list_eas(VFS_FUNC_ARGS_EA_LIST);
+extern int sol_set_ea(VFS_FUNC_ARGS_EA_SET);
+extern int sol_remove_ea(VFS_FUNC_ARGS_EA_REMOVE);
+#endif /* HAVE_SOLARIS_EAS */
+
 #endif /* ATALK_EA_H */
index bca16be1754ec9e70949e3dcdf3d22d2044c2ded..60495a14feab6a41fe0a6f876f3464fea541e0a1 100644 (file)
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#ifdef HAVE_NFSv4_ACLS
-#include <sys/acl.h>
-#endif
-
 #include <atalk/adouble.h>
 #include <atalk/volume.h>
 
+#define VFS_FUNC_ARGS_VALIDUPATH const struct vol *vol, const char *name
+#define VFS_FUNC_VARS_VALIDUPATH vol, name
+
+#define VFS_FUNC_ARGS_CHOWN const struct vol *vol, const char *path, uid_t uid, gid_t gid
+#define VFS_FUNC_VARS_CHOWN vol, path, uid, gid
+
+#define VFS_FUNC_ARGS_RENAMEDIR const struct vol *vol, const char *oldpath, const char *newpath
+#define VFS_FUNC_VARS_RENAMEDIR vol, oldpath, newpath
+
+#define VFS_FUNC_ARGS_DELETECURDIR const struct vol *vol
+#define VFS_FUNC_VARS_DELETECURDIR vol
+
+#define VFS_FUNC_ARGS_SETFILEMODE const struct vol *vol, const char *name, mode_t mode, struct stat *st
+#define VFS_FUNC_VARS_SETFILEMODE vol, name, mode, st
+
+#define VFS_FUNC_ARGS_SETDIRMODE const struct vol *vol,  const char *name, mode_t mode, struct stat *st
+#define VFS_FUNC_VARS_SETDIRMODE vol, name, mode, st
+
+#define VFS_FUNC_ARGS_SETDIRUNIXMODE const struct vol *vol, const char *name, mode_t mode, struct stat *st
+#define VFS_FUNC_VARS_SETDIRUNIXMODE vol, name, mode, st
+
+#define VFS_FUNC_ARGS_SETDIROWNER const struct vol *vol, const char *name, uid_t uid, gid_t gid
+#define VFS_FUNC_VARS_SETDIROWNER vol, name, uid, gid
+
+#define VFS_FUNC_ARGS_DELETEFILE const struct vol *vol, const char *file
+#define VFS_FUNC_VARS_DELETEFILE vol, file
+
+#define VFS_FUNC_ARGS_RENAMEFILE const struct vol *vol, const char *src, const char *dst
+#define VFS_FUNC_VARS_RENAMEFILE vol, src, dst
+
+#define VFS_FUNC_ARGS_ACL const struct vol *vol, const char *path, int cmd, int count, void *aces
+#define VFS_FUNC_VARS_ACL vol, path, cmd, count, aces
+
+#define VFS_FUNC_ARGS_REMOVE_ACL const struct vol *vol, const char *path, int dir
+#define VFS_FUNC_VARS_REMOVE_ACL vol, path, dir
+
+#define VFS_FUNC_ARGS_EA_GETSIZE const struct vol * restrict vol, char * restrict rbuf, int * restrict rbuflen, const char * restrict uname, int oflag, const char * restrict attruname
+#define VFS_FUNC_VARS_EA_GETSIZE vol, rbuf, rbuflen, uname, oflag, attruname
+
+#define VFS_FUNC_ARGS_EA_GETCONTENT const struct vol * restrict vol, char * restrict rbuf, int * restrict rbuflen,  const char * restrict uname, int oflag, const char * restrict attruname, int maxreply
+#define VFS_FUNC_VARS_EA_GETCONTENT vol, rbuf, rbuflen, uname, oflag, attruname, maxreply
+
+#define VFS_FUNC_ARGS_EA_LIST const struct vol * restrict vol, char * restrict attrnamebuf, int * restrict buflen, const char * restrict uname, int oflag
+#define VFS_FUNC_VARS_EA_LIST vol, attrnamebuf, buflen, uname, oflag
+
+#define VFS_FUNC_ARGS_EA_SET const struct vol * restrict vol, const char * restrict uname, const char * restrict attruname, const char * restrict ibuf, size_t attrsize, int oflag
+#define VFS_FUNC_VARS_EA_SET vol, uname, attruname, ibuf, attrsize, oflag
+
+#define VFS_FUNC_ARGS_EA_REMOVE const struct vol * restrict vol, const char * restrict uname, const char * restrict attruname, int oflag
+#define VFS_FUNC_VARS_EA_REMOVE vol, uname, attruname, oflag
+
 struct vfs_ops {
     /* low level adouble fn */
-    char *(*ad_path)(const char *, int);
+    char *(*ad_path)        (const char *, int); /* name is ad_path because it was too
+                                                    much work to change all calls to
+                                                    sth. different eg vfs_path */
 
     /* */
-    int (*validupath)(const struct vol *, const char *);
-    int (*rf_chown)(const struct vol *, const char *path, uid_t owner, gid_t group);
-    int (*rf_renamedir)(const struct vol *, const char *oldpath, const char *newpath);
-    int (*rf_deletecurdir)(const struct vol *);
-    int (*rf_setfilmode)(const struct vol *, const char * name, mode_t mode, struct stat *st);
-    int (*rf_setdirmode)(const struct vol *, const char * name, mode_t mode, struct stat *st);
-    int (*rf_setdirunixmode)(const struct vol *, const char * name, mode_t mode, struct stat *st);
-
-    int (*rf_setdirowner)(const struct vol *, const char *path, uid_t owner, gid_t group);
-
-    int (*rf_deletefile)(const struct vol *, const char * );
-    int (*rf_renamefile)(const struct vol *, const char *oldpath, const char *newpath);
-#ifdef HAVE_NFSv4_ACLS
-    int (*rf_acl)(const struct vol *, const char *path, int cmd, int count, ace_t *aces);
-    int (*rf_remove_acl)(const struct vol *, const char *path, int dir);
-#endif
+    int (*vfs_validupath)    (VFS_FUNC_ARGS_VALIDUPATH);
+    int (*vfs_chown)         (VFS_FUNC_ARGS_CHOWN);
+    int (*vfs_renamedir)     (VFS_FUNC_ARGS_RENAMEDIR);
+    int (*vfs_deletecurdir)  (VFS_FUNC_ARGS_DELETECURDIR);
+    int (*vfs_setfilmode)    (VFS_FUNC_ARGS_SETFILEMODE);
+    int (*vfs_setdirmode)    (VFS_FUNC_ARGS_SETDIRMODE);
+    int (*vfs_setdirunixmode)(VFS_FUNC_ARGS_SETDIRUNIXMODE);
+    int (*vfs_setdirowner)   (VFS_FUNC_ARGS_SETDIROWNER);
+    int (*vfs_deletefile)    (VFS_FUNC_ARGS_DELETEFILE);
+    int (*vfs_renamefile)    (VFS_FUNC_ARGS_RENAMEFILE);
+
+    /* ACLs */
+    int (*vfs_acl)           (VFS_FUNC_ARGS_ACL);
+    int (*vfs_remove_acl)    (VFS_FUNC_ARGS_REMOVE_ACL);
 
     /* Extended Attributes */
-    int (*get_easize)(const struct vol * restrict, char * restrict rbuf, int * restrict rbuflen, const char * restrict uname, int oflag, const char * restrict attruname);
-    int (*get_eacontent)(const struct vol * restrict , char * restrict rbuf, int * restrict rbuflen, const char * restrict uname, int oflag, const char * restrict attruname, int maxreply);
-    int (*list_eas)(const struct vol * restrict , char * restrict attrnamebuf, int * restrict buflen, const char * restrict uname, int oflag);
-    int (*set_ea)(const struct vol * restrict , const char * restrict uname, const char * restrict attruname, const char * restrict ibuf, size_t attrsize, int oflag);
-    int (*remove_ea)(const struct vol * restrict , const char * restrict uname, const char * restrict attruname, int oflag);
+    int (*vfs_ea_getsize)    (VFS_FUNC_ARGS_EA_GETSIZE);
+    int (*vfs_ea_getcontent) (VFS_FUNC_ARGS_EA_GETCONTENT);
+    int (*vfs_ea_list)       (VFS_FUNC_ARGS_EA_LIST);
+    int (*vfs_ea_set)        (VFS_FUNC_ARGS_EA_SET);
+    int (*vfs_ea_remove)     (VFS_FUNC_ARGS_EA_REMOVE);
 };
 
 extern void initvol_vfs(struct vol * restrict vol);
 
-/* VFS inderected funcs ... : */
-/* ...default adouble EAs */
-extern int get_easize(const struct vol * restrict vol, char * restrict rbuf, int * restrict rbuflen, const char * restrict uname, int oflag, const char * restrict attruname);
-extern int get_eacontent(const struct vol * restrict vol, char * restrict rbuf, int * restrict rbuflen, const char * restrict uname, int oflag, const char * restrict attruname, int maxreply);
-extern int list_eas(const struct vol * restrict vol, char * restrict attrnamebuf, int * restrict buflen, const char * restrict uname, int oflag);
-extern int set_ea(const struct vol * restrict vol, const char * restrict uname, const char * restrict attruname, const char * restrict ibuf, size_t attrsize, int oflag);
-extern int remove_ea(const struct vol * restrict vol, const char * restrict uname, const char * restrict attruname, int oflag);
-
-/* ... Solaris native EAs */
-#ifdef HAVE_SOLARIS_EAS
-extern int sol_get_easize(const struct vol * restrict vol, char * restrict rbuf, int * restrict rbuflen, const char * restrict uname, int oflag, const char * restrict attruname);
-extern int sol_get_eacontent(const struct vol * restrict vol, char * restrict rbuf, int * restrict rbuflen, const char * restrict uname, int oflag, char * restrict attruname, int maxreply);
-extern int sol_list_eas(const struct vol * restrict vol, char * restrict attrnamebuf, int * restrict buflen, const char * restrict uname, int oflag);
-extern int sol_set_ea(const struct vol * restrict vol, const char * restrict uname, const char * restrict attruname, const char * restrict ibuf,size_t attrsize, int oflag);
-extern int sol_remove_ea(const struct vol * restrict vol, const char * restrict uname, const char * restrict attruname, int oflag);
-#endif /* HAVE_SOLARIS_EAS */
-
-/* Solaris NFSv4 ACL stuff */
-#ifdef HAVE_NFSv4_ACLS
-extern int get_nfsv4_acl(const char *name, ace_t **retAces);
-extern int remove_acl(const char *name);
-#endif /* HAVE_NFSv4_ACLS */
-
 #endif /* ATALK_VFS_H */
index 9d92d7c9951cd92df80fc0301d99d74ae3a61191..6cfa6132d4e00531fec6b9ab432a843dc05c58a2 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  $Id: ea.c,v 1.2 2009-10-02 14:57:57 franklahm Exp $
+  $Id: ea.c,v 1.3 2009-10-14 15:04:01 franklahm Exp $
   Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
@@ -268,7 +268,6 @@ static char * ea_path(const struct ea * restrict ea,
  * Arguments:
  *
  *    ea            (rw) pointer to struct ea
- *    uname         (r) name of file
  *    attruname     (r) name of EA
  *    attrsize      (r) size of ea
  *    bitmap        (r) bitmap from FP func
@@ -281,7 +280,6 @@ static char * ea_path(const struct ea * restrict ea,
  * Otherwise realloc and put entry at the end. Increments ea->ea_count.
  */
 static int ea_addentry(struct ea * restrict ea,
-                       const char * restrict uname,
                        const char * restrict attruname,
                        size_t attrsize,
                        int bitmap)
@@ -351,8 +349,7 @@ error:
  * Arguments:
  *
  *    ea            (rw) pointer to struct ea
- *    uname         (r) name of EA
- *    attruname     (r) size of ea
+ *    attruname     (r) EA name
  *
  * Returns: new number of EA entries, -1 on error
  *
@@ -363,12 +360,12 @@ error:
  * ea_close and pack_buffer must honor this.
  */
 static int ea_delentry(struct ea * restrict ea,
-                       const char * restrict uname,
                        const char * restrict attruname)
 {
     int ret = 0, count = 0;
 
     if (ea->ea_count == 0) {
+        LOG(log_error, logtype_afpd, "ea_delentry('%s'): illegal ea_count of 0 on deletion");
         return -1;
     }
 
@@ -441,6 +438,7 @@ static int create_ea_header(const char * restrict uname,
     *(uint16_t *)ptr = 0;       /* count */
 
     ea->ea_size = EA_HEADER_SIZE;
+    ea->ea_inited = EA_INITED;
 
 exit:
     if (err != 0) {
@@ -588,12 +586,7 @@ static int ea_open(const struct vol * restrict vol,
         return -1;
     }
 
-    if ((stat(uname, &st)) != 0) {
-        LOG(log_debug, logtype_afpd, "ea_open: cant stat: %s", uname);
-        return -1;
-    }
-
-    /* set it all to 0 */
+    /* Set it all to 0 */
     memset(ea, 0, sizeof(struct ea));
 
     ea->vol = vol;              /* ea_close needs it */
@@ -696,7 +689,9 @@ static int ea_open(const struct vol * restrict vol,
     }
 
 exit:
-    if (ret != 0) {
+    if (ret == 0) {
+        ea->ea_inited = EA_INITED;
+    } else {
         if (ea->ea_data) {
             free(ea->ea_data);
             ea->ea_data = NULL;
@@ -706,6 +701,7 @@ exit:
             ea->ea_fd = -1;
         }
     }
+
     return ret;
 }
 
@@ -733,6 +729,11 @@ static int ea_close(struct ea * restrict ea)
 
     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) {
@@ -1083,7 +1084,7 @@ int set_ea(const struct vol * restrict vol,
         return AFPERR_MISC;
     }
 
-    if ((ea_addentry(&ea, uname, attruname, attrsize, oflag)) == -1) {
+    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;
@@ -1138,7 +1139,7 @@ int remove_ea(const struct vol * restrict vol,
         return AFPERR_MISC;
     }
 
-    if ((ea_delentry(&ea, uname, attruname)) == -1) {
+    if ((ea_delentry(&ea, attruname)) == -1) {
         LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_delentry error", uname);
         ret = AFPERR_MISC;
         goto exit;
@@ -1527,3 +1528,136 @@ int sol_remove_ea(const struct vol * restrict vol,
 
 }
 #endif /* HAVE_SOLARIS_EAS */
+
+/******************************************************************************************
+ * EA VFS funcs that deal with file/dir cp/mv/rm
+ ******************************************************************************************/
+
+int ea_deletefile(VFS_FUNC_ARGS_DELETEFILE)
+{
+    LOG(log_debug, logtype_afpd, "ea_deletefile('%s')", file);
+
+    int count = 0, ret = AFP_OK;
+    struct ea ea;
+
+    /* Open EA stuff */
+    if ((ea_open(vol, 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;
+        }
+    }
+
+    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);
+        return AFPERR_MISC;
+    }
+
+    return ret;
+}
+
+int ea_renamefile(VFS_FUNC_ARGS_RENAMEFILE)
+{
+    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_open(vol, 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() */
+        eapath = ea_path(&srcea, eaname);
+        strcpy(srceapath, eapath);
+        eapath = ea_path(&dstea, eaname);
+
+        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 ((rename( srceapath, 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;
+}
index 0dc4df4e1ed9cdeff46123669313740ac1a52377..b1532bc0e0271a02763f9705bf75a216b5480f98 100644 (file)
 #include <atalk/afp.h>    
 #include <atalk/adouble.h>
 #include <atalk/vfs.h>
+#include <atalk/ea.h>
+#include <atalk/acl.h>
 #include <atalk/logger.h>
 #include <atalk/util.h>
 #include <atalk/volume.h>
 #include <atalk/directory.h>
 
-#ifdef HAVE_NFSv4_ACLS
-extern int remove_acl(const char *name);
-#endif
-
 struct perm {
     uid_t uid;
     gid_t gid;
@@ -91,15 +89,14 @@ static int netatalk_name(const char *name)
         strcasecmp(name,".AppleDesktop");
 }
 
-static int validupath_adouble(const struct vol *vol, const char *name) 
+static int validupath_adouble(VFS_FUNC_ARGS_VALIDUPATH)
 {
     return (vol->v_flags & AFPVOL_USEDOTS) ? 
         netatalk_name(name) && strcasecmp(name,".Parent"): name[0] != '.';
 }                                           
 
 /* ----------------- */
-static int RF_chown_adouble(const struct vol *vol, const char *path, uid_t uid, gid_t gid)
-
+static int RF_chown_adouble(VFS_FUNC_ARGS_CHOWN)
 {
     struct stat st;
     char        *ad_p;
@@ -113,7 +110,7 @@ static int RF_chown_adouble(const struct vol *vol, const char *path, uid_t uid,
 }
 
 /* ----------------- */
-static int RF_renamedir_adouble(const struct vol *vol _U_, const char *oldpath _U_, const char *newpath _U_)
+static int RF_renamedir_adouble(VFS_FUNC_ARGS_RENAMEDIR)
 {
     return 0;
 }
@@ -136,7 +133,7 @@ static int deletecurdir_adouble_loop(struct dirent *de, char *name, void *data _
     return 0;
 }
 
-static int RF_deletecurdir_adouble(const struct vol *vol)
+static int RF_deletecurdir_adouble(VFS_FUNC_ARGS_DELETECURDIR)
 {
     int err;
 
@@ -153,13 +150,13 @@ static int adouble_setfilmode(const char * name, mode_t mode, struct stat *st, m
     return setfilmode(name, ad_hf_mode(mode), st, v_umask);
 }
 
-static int RF_setfilmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
+static int RF_setfilmode_adouble(VFS_FUNC_ARGS_SETFILEMODE)
 {
     return adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_HF ), mode, st, vol->v_umask);
 }
 
 /* ----------------- */
-static int RF_setdirunixmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
+static int RF_setdirunixmode_adouble(VFS_FUNC_ARGS_SETDIRUNIXMODE)
 {
     char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
     int  dropbox = vol->v_flags;
@@ -198,7 +195,7 @@ static int setdirmode_adouble_loop(struct dirent *de _U_, char *name, void *data
     return 0;
 }
 
-static int RF_setdirmode_adouble(const struct vol *vol, const char * name, mode_t mode, struct stat *st _U_)
+static int RF_setdirmode_adouble(VFS_FUNC_ARGS_SETDIRMODE)
 {
     int   dropbox = vol->v_flags;
     mode_t hf_mode = ad_hf_mode(mode);
@@ -233,8 +230,7 @@ static int setdirowner_adouble_loop(struct dirent *de _U_, char *name, void *dat
     return 0;
 }
 
-static int RF_setdirowner_adouble(const struct vol *vol, const char *name, uid_t uid, gid_t gid)
-
+static int RF_setdirowner_adouble(VFS_FUNC_ARGS_SETDIROWNER)
 {
     int           noadouble = vol_noadouble(vol);
     char          *adouble_p;
@@ -267,13 +263,13 @@ static int RF_setdirowner_adouble(const struct vol *vol, const char *name, uid_t
 }
 
 /* ----------------- */
-static int RF_deletefile_adouble(const struct vol *vol, const char *file )
+static int RF_deletefile_adouble(VFS_FUNC_ARGS_DELETEFILE)
 {
        return netatalk_unlink(vol->vfs->ad_path( file, ADFLAGS_HF));
 }
 
 /* ----------------- */
-static int RF_renamefile_adouble(const struct vol *vol, const char *src, const char *dst)
+static int RF_renamefile_adouble(VFS_FUNC_ARGS_RENAMEFILE)
 {
     char  adsrc[ MAXPATHLEN + 1];
     int   err = 0;
@@ -317,7 +313,7 @@ static int RF_renamefile_adouble(const struct vol *vol, const char *src, const c
 }
 
 #ifdef HAVE_NFSv4_ACLS
-static int RF_acl(const struct vol *vol, const char *path, int cmd, int count, ace_t *aces)
+static int RF_solaris_acl(VFS_FUNC_ARGS_ACL)
 {
     static char buf[ MAXPATHLEN + 1];
     struct stat st;
@@ -341,7 +337,7 @@ static int RF_acl(const struct vol *vol, const char *path, int cmd, int count, a
     return 0;
 }
 
-static int RF_remove_acl(const struct vol *vol, const char *path, int dir)
+static int RF_solaris_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL)
 {
     int ret;
     static char buf[ MAXPATHLEN + 1];
@@ -377,8 +373,7 @@ static int ads_chown_loop(struct dirent *de _U_, char *name, void *data, int fla
     return 0;
 }
 
-static int RF_chown_ads(const struct vol *vol, const char *path, uid_t uid, gid_t gid)
-
+static int RF_chown_ads(VFS_FUNC_ARGS_CHOWN)
 {
     struct        stat st;
     char          *ad_p;
@@ -407,7 +402,7 @@ static int deletecurdir_ads1_loop(struct dirent *de _U_, char *name, void *data
     return netatalk_unlink(name);
 }
 
-static int ads_delete_rf(char *name) 
+static int ads_delete_rf(char *name)
 {
     int err;
 
@@ -436,7 +431,7 @@ static int deletecurdir_ads_loop(struct dirent *de, char *name, void *data _U_,
     return ads_delete_rf(name);
 }
 
-static int RF_deletecurdir_ads(const struct vol *vol _U_)
+static int RF_deletecurdir_ads(VFS_FUNC_ARGS_DELETECURDIR)
 {
     int err;
     
@@ -491,13 +486,13 @@ static int ads_setfilmode(const char * name, mode_t mode, struct stat *st, mode_
     return 0;
 }
 
-static int RF_setfilmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
+static int RF_setfilmode_ads(VFS_FUNC_ARGS_SETFILEMODE)
 {
     return ads_setfilmode(ad_dir(vol->vfs->ad_path( name, ADFLAGS_HF )), mode, st, vol->v_umask);
 }
 
 /* ------------------- */
-static int RF_setdirunixmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
+static int RF_setdirunixmode_ads(VFS_FUNC_ARGS_SETDIRUNIXMODE)
 {
     char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
     char   ad_p[ MAXPATHLEN + 1];
@@ -562,7 +557,7 @@ static int setdirmode_ads_loop(struct dirent *de _U_, char *name, void *data, in
     return 0;
 }
 
-static int RF_setdirmode_ads(const struct vol *vol, const char * name, mode_t mode, struct stat *st _U_)
+static int RF_setdirmode_ads(VFS_FUNC_ARGS_SETDIRMODE)
 {
     char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
     char   ad_p[ MAXPATHLEN + 1];
@@ -617,7 +612,7 @@ static int setdirowner_ads_loop(struct dirent *de _U_, char *name, void *data, i
     return 0;
 }
 
-static int RF_setdirowner_ads(const struct vol *vol, const char *name, uid_t uid, gid_t gid)
+static int RF_setdirowner_ads(VFS_FUNC_ARGS_SETDIROWNER)
 {
     int           noadouble = vol_noadouble(vol);
     char          adouble_p[ MAXPATHLEN + 1];
@@ -650,7 +645,7 @@ static int RF_setdirowner_ads(const struct vol *vol, const char *name, uid_t uid
 }
 
 /* ------------------- */
-static int RF_deletefile_ads(const struct vol *vol, const char *file )
+static int RF_deletefile_ads(VFS_FUNC_ARGS_DELETEFILE)
 {
     char *ad_p = ad_dir(vol->vfs->ad_path(file, ADFLAGS_HF ));
 
@@ -658,7 +653,7 @@ static int RF_deletefile_ads(const struct vol *vol, const char *file )
 }
 
 /* --------------------------- */
-static int RF_renamefile_ads(const struct vol *vol, const char *src, const char *dst)
+static int RF_renamefile_ads(VFS_FUNC_ARGS_RENAMEFILE)
 {
     char  adsrc[ MAXPATHLEN + 1];
     int   err = 0;
@@ -707,14 +702,14 @@ static int RF_renamefile_ads(const struct vol *vol, const char *src, const char
 /*************************************************************************
  * osx adouble format 
  ************************************************************************/
-static int validupath_osx(const struct vol *vol, const char *name) 
+static int validupath_osx(VFS_FUNC_ARGS_VALIDUPATH)
 {
     return strncmp(name,"._", 2) && (
       (vol->v_flags & AFPVOL_USEDOTS) ? netatalk_name(name): name[0] != '.');
 }             
 
 /* ---------------- */
-static int RF_renamedir_osx(const struct vol *vol, const char *oldpath, const char *newpath)
+static int RF_renamedir_osx(VFS_FUNC_ARGS_RENAMEDIR)
 {
     /* We simply move the corresponding ad file as well */
     char   tempbuf[258]="._";
@@ -722,33 +717,31 @@ static int RF_renamedir_osx(const struct vol *vol, const char *oldpath, const ch
 }
 
 /* ---------------- */
-static int RF_deletecurdir_osx(const struct vol *vol)
+static int RF_deletecurdir_osx(VFS_FUNC_ARGS_DELETECURDIR)
 {
     return netatalk_unlink( vol->vfs->ad_path(".",0) );
 }
 
 /* ---------------- */
-static int RF_setdirunixmode_osx(const struct vol *vol, const char * name, mode_t mode, struct stat *st)
+static int RF_setdirunixmode_osx(VFS_FUNC_ARGS_SETDIRUNIXMODE)
 {
     return adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_DIR ), mode, st, vol->v_umask);
 }
 
 /* ---------------- */
-static int 
-RF_setdirmode_osx(const struct vol *vol _U_, const char *name _U_, mode_t mode _U_, struct stat *st _U_)
+static int RF_setdirmode_osx(VFS_FUNC_ARGS_SETDIRMODE)
 {
     return 0;
 }
 
 /* ---------------- */
-static int 
-RF_setdirowner_osx(const struct vol *vol _U_, const char *path _U_, uid_t uid _U_, gid_t gid _U_)
+static int RF_setdirowner_osx(VFS_FUNC_ARGS_SETDIROWNER)
 {
        return 0;
 }
 
 /* ---------------- */
-static int RF_renamefile_osx(const struct vol *vol, const char *src, const char *dst)
+static int RF_renamefile_osx(VFS_FUNC_ARGS_RENAMEFILE)
 {
     char  adsrc[ MAXPATHLEN + 1];
     int   err = 0;
@@ -767,6 +760,102 @@ static int RF_renamefile_osx(const struct vol *vol, const char *src, const char
     return 0;
 }
 
+/********************************************************************************************
+ * VFS chaining
+ ********************************************************************************************/
+
+/* 
+ * Up until we really start stacking many VFS modules on top of one another or use
+ * dynamic module loading like we do for UAMs, up until then we just stack VFS modules
+ * via an fixed size array.
+ * All VFS funcs must return AFP_ERR codes. When a func in the chain returns an error
+ * this error code will be returned to the caller, BUT the chain in followed and all
+ * following funcs are called in order to give them a chance.
+ */
+
+/* 
+ * Currently the maximum will be:
+ * main adouble module + EA module + ACL module + NULL = 4.
+ * NULL is an end of array marker.
+ */
+static struct vfs_ops *vfs[4] = { NULL };
+
+/* 
+ * Define most VFS funcs with macros as they all do the same.
+ * Only "ad_path" and "validupath" will NOT do stacking and only
+ * call the func from the first module.
+ */
+#define VFS_MFUNC(name, args, vars) \
+    static int vfs_ ## name(args) \
+    { \
+        int i = 0, ret = AFP_OK, err; \
+        while (vfs[i]) { \
+            if (vfs[i]->vfs_ ## name) { \
+                err = vfs[i]->vfs_ ## name (vars); \
+                if ((ret == AFP_OK) && (err != AFP_OK)) \
+                    ret = err; \
+            } \
+            i ++; \
+        } \
+        return ret; \
+    }
+
+VFS_MFUNC(chown, VFS_FUNC_ARGS_CHOWN, VFS_FUNC_VARS_CHOWN)
+VFS_MFUNC(renamedir, VFS_FUNC_ARGS_RENAMEDIR, VFS_FUNC_VARS_RENAMEDIR) 
+VFS_MFUNC(deletecurdir, VFS_FUNC_ARGS_DELETECURDIR, VFS_FUNC_VARS_DELETECURDIR)
+VFS_MFUNC(setfilmode, VFS_FUNC_ARGS_SETFILEMODE, VFS_FUNC_VARS_SETFILEMODE)
+VFS_MFUNC(setdirmode, VFS_FUNC_ARGS_SETDIRMODE, VFS_FUNC_VARS_SETDIRMODE)
+VFS_MFUNC(setdirunixmode, VFS_FUNC_ARGS_SETDIRUNIXMODE, VFS_FUNC_VARS_SETDIRUNIXMODE)
+VFS_MFUNC(setdirowner, VFS_FUNC_ARGS_SETDIROWNER, VFS_FUNC_VARS_SETDIROWNER)
+VFS_MFUNC(deletefile, VFS_FUNC_ARGS_DELETEFILE, VFS_FUNC_VARS_DELETEFILE)
+VFS_MFUNC(renamefile, VFS_FUNC_ARGS_RENAMEFILE, VFS_FUNC_VARS_RENAMEFILE)
+VFS_MFUNC(acl, VFS_FUNC_ARGS_ACL, VFS_FUNC_VARS_ACL)
+VFS_MFUNC(remove_acl, VFS_FUNC_ARGS_REMOVE_ACL, VFS_FUNC_VARS_REMOVE_ACL)
+VFS_MFUNC(ea_getsize, VFS_FUNC_ARGS_EA_GETSIZE, VFS_FUNC_VARS_EA_GETSIZE)
+VFS_MFUNC(ea_getcontent, VFS_FUNC_ARGS_EA_GETCONTENT, VFS_FUNC_VARS_EA_GETCONTENT)
+VFS_MFUNC(ea_list, VFS_FUNC_ARGS_EA_LIST, VFS_FUNC_VARS_EA_LIST)
+VFS_MFUNC(ea_set, VFS_FUNC_ARGS_EA_SET, VFS_FUNC_VARS_EA_SET)
+VFS_MFUNC(ea_remove, VFS_FUNC_ARGS_EA_REMOVE, VFS_FUNC_VARS_EA_REMOVE)
+
+static char *vfs_path(const char *path, int flags)
+{
+    return vfs[0]->ad_path(path, flags);
+}
+
+static int vfs_validupath(VFS_FUNC_ARGS_VALIDUPATH)
+{
+    return vfs[0]->vfs_validupath(VFS_FUNC_VARS_VALIDUPATH);
+}
+
+/*
+ * These function pointers get called from the lib users via vol->vfs->func.
+ * These funcs are defined via the macros above.
+ */
+struct vfs_ops vfs_master_funcs = {
+    vfs_path,
+    vfs_validupath,
+    vfs_chown,
+    vfs_renamedir,
+    vfs_deletecurdir,
+    vfs_setfilmode,
+    vfs_setdirmode,
+    vfs_setdirunixmode,
+    vfs_setdirowner,
+    vfs_deletefile,
+    vfs_renamefile,
+    vfs_acl,
+    vfs_remove_acl,
+    vfs_ea_getsize,
+    vfs_ea_getcontent,
+    vfs_ea_list,
+    vfs_ea_set,
+    vfs_ea_remove
+};
+
+/* 
+ * Primary adouble modules: default, osx, sfm
+ */
+
 static struct vfs_ops netatalk_adouble = {
     /* ad_path:           */ ad_path,
     /* validupath:        */ validupath_adouble,
@@ -779,10 +868,6 @@ static struct vfs_ops netatalk_adouble = {
     /* rf_setdirowner:    */ RF_setdirowner_adouble,
     /* rf_deletefile:     */ RF_deletefile_adouble,
     /* rf_renamefile:     */ RF_renamefile_adouble,
-#ifdef HAVE_NFSv4_ACLS
-    /* rf_acl:            */ RF_acl,
-    /* rf_remove_acl      */ RF_remove_acl
-#endif
 };
 
 static struct vfs_ops netatalk_adouble_osx = {
@@ -814,18 +899,90 @@ static struct vfs_ops netatalk_adouble_sfm = {
     /* rf_renamefile:    */ RF_renamefile_ads,
 };
 
+/* 
+ * Secondary vfs modules for Extended Attributes
+ */
+
+struct vfs_ops netatalk_ea_adouble = {
+    /* ad_path:           */ NULL,
+    /* validupath:        */ NULL,
+    /* rf_chown:          */ NULL,
+    /* rf_renamedir:      */ NULL,
+    /* rf_deletecurdir:   */ NULL,
+    /* rf_setfilmode:     */ NULL,
+    /* rf_setdirmode:     */ NULL,
+    /* rf_setdirunixmode: */ NULL,
+    /* rf_setdirowner:    */ NULL,
+    /* rf_deletefile:     */ ea_deletefile,
+    /* rf_renamefile:     */ ea_renamefile,
+    /* rf_acl:            */ NULL,
+    /* rf_remove_acl      */ NULL,
+    /* ea_getsize         */ get_easize,
+    /* ea_getcontent      */ get_eacontent,
+    /* ea_list            */ list_eas,
+    /* ea_set             */ set_ea,
+    /* ea_remove          */ remove_ea
+};
+
+#ifdef HAVE_SOLARIS_EAS
+struct vfs_ops netatalk_ea_solaris = {
+    /* ad_path:           */ NULL,
+    /* validupath:        */ NULL,
+    /* rf_chown:          */ NULL,
+    /* rf_renamedir:      */ NULL,
+    /* rf_deletecurdir:   */ NULL,
+    /* rf_setfilmode:     */ NULL,
+    /* rf_setdirmode:     */ NULL,
+    /* rf_setdirunixmode: */ NULL,
+    /* rf_setdirowner:    */ NULL,
+    /* rf_deletefile:     */ NULL,
+    /* rf_renamefile:     */ NULL,
+    /* rf_acl:            */ NULL,
+    /* rf_remove_acl      */ NULL,
+    /* ea_getsize         */ sol_get_easize,
+    /* ea_getcontent      */ sol_get_eacontent,
+    /* ea_list            */ sol_list_eas,
+    /* ea_set             */ sol_set_ea,
+    /* ea_remove          */ sol_remove_ea
+};
+#endif
+
+/* 
+ * Tertiary attributes for ACLs
+ */
+
+#ifdef HAVE_NFSv4_ACLS
+struct vfs_ops netatalk_solaris_acl_adouble = {
+    /* ad_path:           */ NULL,
+    /* validupath:        */ NULL,
+    /* rf_chown:          */ NULL,
+    /* rf_renamedir:      */ NULL,
+    /* rf_deletecurdir:   */ NULL,
+    /* rf_setfilmode:     */ NULL,
+    /* rf_setdirmode:     */ NULL,
+    /* rf_setdirunixmode: */ NULL,
+    /* rf_setdirowner:    */ NULL,
+    /* rf_deletefile:     */ NULL,
+    /* rf_renamefile:     */ NULL,
+    /* rf_acl:            */ RF_solaris_acl,
+    /* rf_remove_acl      */ RF_remove_acl
+};
+#endif
+
 /* ---------------- */
 void initvol_vfs(struct vol *vol)
 {
-    /* adouble stuff */
+    vol->vfs = &vfs_master_funcs;
+
+    /* Default adouble stuff */
     if (vol->v_adouble == AD_VERSION2_OSX) {
-        vol->vfs = &netatalk_adouble_osx;
+        vfs[0] = &netatalk_adouble_osx;
     }
     else if (vol->v_adouble == AD_VERSION1_SFM) {
-        vol->vfs = &netatalk_adouble_sfm;
+        vfs[0] = &netatalk_adouble_sfm;
     }
     else {
-        vol->vfs = &netatalk_adouble;
+        vfs[0] = &netatalk_adouble;
     }
 
     /* Extended Attributes */
@@ -833,12 +990,7 @@ void initvol_vfs(struct vol *vol)
 
 #ifdef HAVE_SOLARIS_EAS
         LOG(log_debug, logtype_afpd, "initvol_vfs: Enabling EA support with Solaris native EAs.");
-
-        netatalk_adouble.list_eas = sol_list_eas;
-        netatalk_adouble.get_easize = sol_get_easize;
-        netatalk_adouble.get_eacontent = sol_get_eacontent;
-        netatalk_adouble.set_ea = sol_set_ea;
-        netatalk_adouble.remove_ea = sol_remove_ea;
+        vfs[1] = &netatalk_ea_solaris;
 #else
         LOG(log_error, logtype_afpd, "initvol_vfs: Can't enable Solaris EA support.");
         goto enable_adea;
@@ -847,12 +999,12 @@ void initvol_vfs(struct vol *vol)
     enable_adea:
         /* default: AFPVOL_EA_AD */
         LOG(log_debug, logtype_afpd, "initvol_vfs: Enabling EA support with adouble files.");
-
-        netatalk_adouble.set_ea = set_ea;
-        netatalk_adouble.list_eas = list_eas;
-        netatalk_adouble.get_easize = get_easize;
-        netatalk_adouble.get_eacontent = get_eacontent;
-        netatalk_adouble.remove_ea = remove_ea;
+        vfs[1] = &netatalk_ea_adouble;
     }
+
+    /* ACLs */
+#ifdef HAVE_NFSv4_ACLS
+    vfs[2] = &netatalk_solaris_acl_adouble;
+#endif
 }