/*
Copyright (c) 2004 Didier Gautheron
+ Copyright (c) 2009 Frank Lahm
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
#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
#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/vfs.h>
#include <atalk/directory.h>
-
-#if 0
-#include "extattrs.h"
-#endif
-
-#ifdef HAVE_NFSv4_ACLS
-extern int remove_acl(const char *name);
-#endif
+#include <atalk/unix.h>
struct perm {
uid_t uid;
static int netatalk_name(const char *name)
{
- return strcasecmp(name,".AppleDB") &&
- strcasecmp(name,".AppleDouble") &&
+ return strcasecmp(name,".AppleDouble") &&
+ strcasecmp(name,".AppleDB") &&
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] != '.';
+ if (name[0] != '.')
+ return 1;
+
+ if (!(vol->v_flags & AFPVOL_USEDOTS))
+ return 0;
+
+ return netatalk_name(name) && strcasecmp(name,".Parent");
}
/* ----------------- */
-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;
- ad_p = vol->vfs->ad_path(path, ADFLAGS_HF );
+ ad_p = vol->ad_path(path, ADFLAGS_HF );
if ( stat( ad_p, &st ) < 0 )
return 0; /* ignore */
}
/* ----------------- */
-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;
}
return 0;
}
-static int RF_deletecurdir_adouble(const struct vol *vol)
+static int RF_deletecurdir_adouble(VFS_FUNC_ARGS_DELETECURDIR)
{
int err;
as well. */
if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_adouble_loop, NULL, 1, vol->v_umask)))
return err;
- return netatalk_rmdir( ".AppleDouble" );
+ return netatalk_rmdir(-1, ".AppleDouble" );
}
/* ----------------- */
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);
+ return adouble_setfilmode(vol->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 );
+ char *adouble = vol->ad_path(name, ADFLAGS_DIR );
int dropbox = vol->v_flags;
if (dir_rx_set(mode)) {
return -1;
}
- if (adouble_setfilmode(vol->vfs->ad_path( name, ADFLAGS_DIR ), mode, st, vol->v_umask) < 0)
+ if (adouble_setfilmode(vol->ad_path(name, ADFLAGS_DIR ), mode, st, vol->v_umask) < 0)
return -1;
if (!dir_rx_set(mode)) {
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);
- char *adouble = vol->vfs->ad_path( name, ADFLAGS_DIR );
+ char *adouble = vol->ad_path(name, ADFLAGS_DIR );
char *adouble_p = ad_dir(adouble);
if (dir_rx_set(mode)) {
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;
owner.uid = uid;
owner.gid = gid;
- adouble_p = ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR ));
+ adouble_p = ad_dir(vol->ad_path(name, ADFLAGS_DIR ));
if (for_each_adouble("setdirowner", adouble_p, setdirowner_adouble_loop, &owner, noadouble, vol->v_umask))
return -1;
}
/* ----------------- */
-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));
+ return netatalk_unlinkat(dirfd, vol->ad_path(file, ADFLAGS_HF));
}
/* ----------------- */
-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;
- strcpy( adsrc, vol->vfs->ad_path( src, 0 ));
- if (unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) < 0) {
+ strcpy( adsrc, vol->ad_path(src, 0 ));
+ if (unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) < 0) {
struct stat st;
err = errno;
if (errno == ENOENT) {
struct adouble ad;
- if (stat(adsrc, &st)) /* source has no ressource fork, */
+ 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.
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);
- if (!unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) )
+ if (!unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) )
err = 0;
else
err = errno;
}
#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;
+ int len;
if ((stat(path, &st)) != 0)
return -1;
if (S_ISDIR(st.st_mode)) {
- if ((snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path)) < 0)
+ len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
+ if (len < 0 || len >= MAXPATHLEN)
return -1;
/* set acl on .AppleDouble dir first */
if ((acl(buf, cmd, count, aces)) != 0)
return -1;
/* now set ACL on ressource fork */
- if ((acl(vol->vfs->ad_path(path, ADFLAGS_DIR), cmd, count, aces)) != 0)
+ if ((acl(vol->ad_path(path, ADFLAGS_DIR), cmd, count, aces)) != 0)
return -1;
} else
/* set ACL on ressource fork */
- if ((acl(vol->vfs->ad_path(path, ADFLAGS_HF), cmd, count, aces)) != 0)
+ if ((acl(vol->ad_path(path, ADFLAGS_HF), cmd, count, aces)) != 0)
return -1;
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];
+ int len;
if (dir) {
- if ((snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path)) < 0)
+ len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
+ if (len < 0 || len >= MAXPATHLEN)
return AFPERR_MISC;
/* remove ACL from .AppleDouble/.Parent first */
- if ((ret = remove_acl(vol->vfs->ad_path(path, ADFLAGS_DIR))) != AFP_OK)
+ if ((ret = remove_acl(vol->ad_path(path, ADFLAGS_DIR))) != AFP_OK)
return ret;
/* now remove from .AppleDouble dir */
if ((ret = remove_acl(buf)) != AFP_OK)
return ret;
} else
/* remove ACL from ressource fork */
- if ((ret = remove_acl(vol->vfs->ad_path(path, ADFLAGS_HF))) != AFP_OK)
+ if ((ret = remove_acl(vol->ad_path(path, ADFLAGS_HF))) != AFP_OK)
return ret;
return AFP_OK;
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;
owner.gid = gid;
- ad_p = ad_dir(vol->vfs->ad_path(path, ADFLAGS_HF ));
+ ad_p = ad_dir(vol->ad_path(path, ADFLAGS_HF ));
if ( stat( ad_p, &st ) < 0 ) {
/* ignore */
return netatalk_unlink(name);
}
-static int ads_delete_rf(char *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;
- return netatalk_rmdir(name);
+ 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_)
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;
-
+
/* 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( ".AppleDouble" );
+
+ return netatalk_rmdir(-1, ".AppleDouble" );
}
/* ------------------- */
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);
+ return ads_setfilmode(ad_dir(vol->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 *adouble = vol->ad_path(name, ADFLAGS_DIR );
char ad_p[ MAXPATHLEN + 1];
int dropbox = vol->v_flags;
return -1;
}
- if (ads_setfilmode(ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR)), mode, st, vol->v_umask) < 0)
+ if (ads_setfilmode(ad_dir(vol->ad_path(name, ADFLAGS_DIR)), mode, st, vol->v_umask) < 0)
return -1;
if (!dir_rx_set(mode)) {
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 *adouble = vol->ad_path(name, ADFLAGS_DIR );
char ad_p[ MAXPATHLEN + 1];
struct dir_mode param;
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];
owner.uid = uid;
owner.gid = gid;
- strlcpy(adouble_p, ad_dir(vol->vfs->ad_path( name, ADFLAGS_DIR )), sizeof(adouble_p));
+ 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;
}
/* ------------------- */
-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 ));
+ 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);
+ }
- return ads_delete_rf(ad_p);
+exit:
+ if (cwd != -1)
+ close(cwd);
+
+ return ret;
}
/* --------------------------- */
-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;
- strcpy( adsrc, ad_dir(vol->vfs->ad_path( src, 0 )));
- if (unix_rename( adsrc, ad_dir(vol->vfs->ad_path( dst, 0 ))) < 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 (stat(adsrc, &st)) /* source has no ressource fork, */
+ if (lstatat(dirfd, adsrc, &st)) /* source has no ressource fork, */
return 0;
/* We are here because :
ad_close(&ad, ADFLAGS_HF);
/* We must delete it */
- RF_deletefile_ads(vol, dst );
- if (!unix_rename( adsrc, ad_dir(vol->vfs->ad_path( dst, 0 ))) )
+ RF_deletefile_ads(vol, -1, dst );
+ if (!unix_rename(dirfd, adsrc, -1, ad_dir(vol->ad_path(dst, 0 ))) )
err = 0;
else
err = errno;
/*************************************************************************
* 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] != '.');
}
/* ---------------- */
-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]="._";
- return rename(vol->vfs->ad_path(oldpath,0),strcat(tempbuf,newpath));
+ return unix_rename(dirfd, vol->ad_path(oldpath,0), -1, strcat(tempbuf,newpath));
}
/* ---------------- */
-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) );
+ return netatalk_unlink( vol->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);
+ return adouble_setfilmode(vol->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;
}
/* ---------------- */
-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;
- strcpy( adsrc, vol->vfs->ad_path( src, 0 ));
+ strcpy( adsrc, vol->ad_path(src, 0 ));
- if (unix_rename( adsrc, vol->vfs->ad_path( dst, 0 )) < 0) {
+ if (unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) < 0) {
struct stat st;
err = errno;
- if (errno == ENOENT && stat(adsrc, &st)) /* source has no ressource fork, */
+ if (errno == ENOENT && lstatat(dirfd, adsrc, &st)) /* source has no ressource fork, */
return 0;
errno = err;
return -1;
return 0;
}
-struct vfs_ops netatalk_adouble = {
- /* ad_path: */ ad_path,
- /* validupath: */ validupath_adouble,
- /* rf_chown: */ RF_chown_adouble,
- /* rf_renamedir: */ RF_renamedir_adouble,
- /* rf_deletecurdir: */ RF_deletecurdir_adouble,
- /* rf_setfilmode: */ RF_setfilmode_adouble,
- /* rf_setdirmode: */ RF_setdirmode_adouble,
- /* rf_setdirunixmode: */ RF_setdirunixmode_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
+/********************************************************************************************
+ * 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.
+ */
+
+/*
+ * 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 (vol->vfs_modules[i]) { \
+ if (vol->vfs_modules[i]->vfs_ ## name) { \
+ err = vol->vfs_modules[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(copyfile, VFS_FUNC_ARGS_COPYFILE, VFS_FUNC_VARS_COPYFILE)
+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 int vfs_validupath(VFS_FUNC_ARGS_VALIDUPATH)
+{
+ return vol->vfs_modules[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.
+ */
+static struct vfs_ops vfs_master_funcs = {
+ vfs_validupath,
+ vfs_chown,
+ vfs_renamedir,
+ vfs_deletecurdir,
+ vfs_setfilmode,
+ vfs_setdirmode,
+ vfs_setdirunixmode,
+ vfs_setdirowner,
+ vfs_deletefile,
+ vfs_renamefile,
+ vfs_copyfile,
+ 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 = {
+ /* vfs_validupath: */ validupath_adouble,
+ /* vfs_chown: */ RF_chown_adouble,
+ /* vfs_renamedir: */ RF_renamedir_adouble,
+ /* vfs_deletecurdir: */ RF_deletecurdir_adouble,
+ /* vfs_setfilmode: */ RF_setfilmode_adouble,
+ /* vfs_setdirmode: */ RF_setdirmode_adouble,
+ /* vfs_setdirunixmode:*/ RF_setdirunixmode_adouble,
+ /* vfs_setdirowner: */ RF_setdirowner_adouble,
+ /* vfs_deletefile: */ RF_deletefile_adouble,
+ /* vfs_renamefile: */ RF_renamefile_adouble,
+ /* vfs_copyfile: */ NULL,
+ NULL
};
-struct vfs_ops netatalk_adouble_osx = {
- /* ad_path: */ ad_path_osx,
- /* validupath: */ validupath_osx,
- /* rf_chown: */ RF_chown_adouble,
- /* rf_renamedir: */ RF_renamedir_osx,
- /* rf_deletecurdir: */ RF_deletecurdir_osx,
- /* rf_setfilmode: */ RF_setfilmode_adouble,
- /* rf_setdirmode: */ RF_setdirmode_osx,
- /* rf_setdirunixmode:*/ RF_setdirunixmode_osx,
- /* rf_setdirowner: */ RF_setdirowner_osx,
- /* rf_deletefile: */ RF_deletefile_adouble,
- /* rf_renamefile: */ RF_renamefile_osx,
+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 */
-struct vfs_ops netatalk_adouble_sfm = {
- /* ad_path: */ ad_path_sfm,
- /* validupath: */ validupath_adouble,
- /* rf_chown: */ RF_chown_ads,
- /* rf_renamedir: */ RF_renamedir_adouble,
- /* rf_deletecurdir: */ RF_deletecurdir_ads,
- /* rf_setfilmode: */ RF_setfilmode_ads,
- /* rf_setdirmode: */ RF_setdirmode_ads,
- /* rf_setdirunixmode:*/ RF_setdirunixmode_ads,
- /* rf_setdirowner: */ RF_setdirowner_ads,
- /* rf_deletefile: */ RF_deletefile_ads,
- /* rf_renamefile: */ RF_renamefile_ads,
+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,
+ NULL
};
+/*
+ * Secondary vfs modules for Extended Attributes
+ */
+
+static struct vfs_ops netatalk_ea_adouble = {
+ /* vfs_validupath: */ NULL,
+ /* vfs_chown: */ ea_chown,
+ /* vfs_renamedir: */ NULL, /* ok */
+ /* vfs_deletecurdir: */ NULL, /* ok */
+ /* vfs_setfilmode: */ ea_chmod_file,
+ /* vfs_setdirmode: */ NULL, /* ok */
+ /* vfs_setdirunixmode:*/ ea_chmod_dir,
+ /* vfs_setdirowner: */ NULL, /* ok */
+ /* vfs_deletefile: */ ea_deletefile,
+ /* vfs_renamefile: */ ea_renamefile,
+ /* vfs_copyfile */ ea_copyfile,
+ /* vfs_acl: */ NULL,
+ /* vfs_remove_acl */ NULL,
+ /* vfs_getsize */ get_easize,
+ /* vfs_getcontent */ get_eacontent,
+ /* vfs_list */ list_eas,
+ /* vfs_set */ set_ea,
+ /* vfs_remove */ remove_ea
+};
+
+static struct vfs_ops netatalk_ea_sys = {
+ /* 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,
+ /* vfs_copyfile: */ sys_ea_copyfile,
+ /* rf_acl: */ NULL,
+ /* rf_remove_acl */ NULL,
+ /* ea_getsize */ sys_get_easize,
+ /* ea_getcontent */ sys_get_eacontent,
+ /* ea_list */ sys_list_eas,
+ /* ea_set */ sys_set_ea,
+ /* ea_remove */ sys_remove_ea
+};
+
+/*
+ * Tertiary VFS modules for ACLs
+ */
+
+#ifdef HAVE_NFSv4_ACLS
+static struct vfs_ops netatalk_solaris_acl_adouble = {
+ /* 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,
+ /* vfs_copyfile */ NULL,
+ /* rf_acl: */ RF_solaris_acl,
+ /* rf_remove_acl */ RF_solaris_remove_acl,
+ NULL
+};
+#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;
+ vol->vfs_modules[0] = &netatalk_adouble_osx;
+ vol->ad_path = ad_path_osx;
}
else if (vol->v_adouble == AD_VERSION1_SFM) {
- vol->vfs = &netatalk_adouble_sfm;
+ vol->vfs_modules[0] = &netatalk_adouble_sfm;
+ vol->ad_path = ad_path_sfm;
}
else {
- vol->vfs = &netatalk_adouble;
+ vol->vfs_modules[0] = &netatalk_adouble;
+ vol->ad_path = ad_path;
}
/* Extended Attributes */
- if (vol->v_vfs_ea == AFPVOL_EA_SOLARIS) {
-
-#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;
-#else
- LOG(log_error, logtype_afpd, "initvol_vfs: Can't enable Solaris EA support.");
- goto enable_adea;
-#endif
+ if (vol->v_vfs_ea == AFPVOL_EA_SYS) {
+ LOG(log_debug, logtype_afpd, "initvol_vfs: enabling EA support with native EAs");
+ vol->vfs_modules[1] = &netatalk_ea_sys;
+ } else if (vol->v_vfs_ea == AFPVOL_EA_AD) {
+ LOG(log_debug, logtype_afpd, "initvol_vfs: enabling EA support with adouble files");
+ vol->vfs_modules[1] = &netatalk_ea_adouble;
} else {
- 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;
+ LOG(log_debug, logtype_afpd, "initvol_vfs: volume without EA support");
}
-}
+ /* ACLs */
+#ifdef HAVE_NFSv4_ACLS
+ vol->vfs_modules[2] = &netatalk_solaris_acl_adouble;
+#endif
+}