#include "config.h"
#endif /* HAVE_CONFIG_H */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <libgen.h>
#include <atalk/afp.h>
#include <atalk/adouble.h>
#include <atalk/vfs.h>
#include <atalk/directory.h>
#include <atalk/unix.h>
+#include <atalk/errchk.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
struct perm {
uid_t uid;
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" );
}
/* ----------------- */
/* ----------------- */
static int RF_deletefile_adouble(VFS_FUNC_ARGS_DELETEFILE)
{
- return netatalk_unlink(vol->ad_path(file, ADFLAGS_HF));
+ return netatalk_unlinkat(dirfd, vol->ad_path(file, ADFLAGS_HF));
}
/* ----------------- */
int err = 0;
strcpy( adsrc, vol->ad_path(src, 0 ));
- if (unix_rename( adsrc, vol->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) {
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->ad_path(dst, 0 )) )
+ if (!unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) )
err = 0;
else
err = errno;
return 0;
}
-#ifdef HAVE_NFSv4_ACLS
+static int RF_copyfile_adouble(VFS_FUNC_ARGS_COPYFILE)
+/* const struct vol *vol, int sfd, const char *src, const char *dst */
+{
+ EC_INIT;
+ bstring s = NULL, d = NULL;
+ char *dup1 = NULL;
+ char *dup2 = NULL;
+ char *dup3 = NULL;
+ char *dup4 = NULL;
+ const char *name = NULL;
+ const char *dir = NULL;
+
+ struct stat st;
+ EC_ZERO(stat(dst, &st));
+
+ if (S_ISDIR(st.st_mode)) {
+ /* build src path to AppleDouble file*/
+ EC_NULL(s = bfromcstr(src));
+ EC_ZERO(bcatcstr(s, "/.AppleDouble/.Parent"));
+
+ /* build dst path to AppleDouble file*/
+ EC_NULL(d = bfromcstr(dst));
+ EC_ZERO(bcatcstr(d, "/.AppleDouble/.Parent"));
+ } else {
+ /* get basename */
+
+ /* build src path to AppleDouble file*/
+ EC_NULL(dup1 = strdup(src));
+ EC_NULL(name = basename(strdup(dup1)));
+
+ EC_NULL(dup2 = strdup(src));
+ EC_NULL(dir = dirname(dup2));
+ EC_NULL(s = bfromcstr(dir));
+ EC_ZERO(bcatcstr(s, "/.AppleDouble/"));
+ EC_ZERO(bcatcstr(s, name));
+
+ /* build dst path to AppleDouble file*/
+ EC_NULL(dup4 = strdup(dst));
+ EC_NULL(name = basename(strdup(dup4)));
+
+ EC_NULL(dup3 = strdup(dst));
+ EC_NULL(dir = dirname(dup3));
+ EC_NULL(d = bfromcstr(dir));
+ EC_ZERO(bcatcstr(d, "/.AppleDouble/"));
+ EC_ZERO(bcatcstr(d, name));
+ }
+
+ EC_ZERO(copy_file(sfd, cfrombstr(s), cfrombstr(d), 0666));
+
+EC_CLEANUP:
+ bdestroy(s);
+ bdestroy(d);
+ if (dup1) free(dup1);
+ if (dup2) free(dup2);
+ if (dup3) free(dup3);
+ if (dup4) free(dup4);
+
+ EC_EXIT;
+}
+
+#ifdef HAVE_SOLARIS_ACLS
static int RF_solaris_acl(VFS_FUNC_ARGS_ACL)
{
static char buf[ MAXPATHLEN + 1];
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;
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_vfs(vol->ad_path(path, ADFLAGS_DIR))) != AFP_OK)
return ret;
/* now remove from .AppleDouble dir */
- if ((ret = remove_acl(buf)) != AFP_OK)
+ if ((ret = remove_acl_vfs(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_vfs(vol->ad_path(path, ADFLAGS_HF))) != AFP_OK)
return ret;
return AFP_OK;
}
#endif
+#ifdef HAVE_POSIX_ACLS
+static int RF_posix_acl(VFS_FUNC_ARGS_ACL)
+{
+ EC_INIT;
+ static char buf[ MAXPATHLEN + 1];
+ struct stat st;
+ int len;
+
+ if (S_ISDIR(st.st_mode)) {
+ len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
+ if (len < 0 || len >= MAXPATHLEN)
+ EC_FAIL;
+ /* set acl on .AppleDouble dir first */
+ EC_ZERO_LOG(acl_set_file(buf, type, acl));
+
+ if (type == ACL_TYPE_ACCESS)
+ /* set ACL on ressource fork (".Parent") too */
+ EC_ZERO_LOG(acl_set_file(vol->ad_path(path, ADFLAGS_DIR), type, acl));
+ } else {
+ /* set ACL on ressource fork */
+ EC_ZERO_LOG(acl_set_file(vol->ad_path(path, ADFLAGS_HF), type, acl));
+ }
+
+EC_CLEANUP:
+ if (ret != 0)
+ return AFPERR_MISC;
+ return AFP_OK;
+}
+
+static int RF_posix_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL)
+{
+ EC_INIT;
+ static char buf[ MAXPATHLEN + 1];
+ int len;
+
+ if (dir) {
+ len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
+ if (len < 0 || len >= MAXPATHLEN)
+ return AFPERR_MISC;
+ /* remove ACL from .AppleDouble/.Parent first */
+ EC_ZERO_LOG_ERR(remove_acl_vfs(vol->ad_path(path, ADFLAGS_DIR)), AFPERR_MISC);
+
+ /* now remove from .AppleDouble dir */
+ EC_ZERO_LOG_ERR(remove_acl_vfs(buf), AFPERR_MISC);
+ } else {
+ /* remove ACL from ressource fork */
+ EC_ZERO_LOG_ERR(remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF)), AFPERR_MISC);
+ }
+
+EC_CLEANUP:
+ EC_EXIT;
+}
+#endif
+
/*********************************************************************************
* sfm adouble format
*********************************************************************************/
*/
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_)
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" );
}
/* ------------------- */
/* ------------------- */
static int RF_deletefile_ads(VFS_FUNC_ARGS_DELETEFILE)
{
- char *ad_p = ad_dir(vol->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);
+ }
+
+exit:
+ if (cwd != -1)
+ close(cwd);
- return ads_delete_rf(ad_p);
+ return ret;
}
/* --------------------------- */
int err = 0;
strcpy( adsrc, ad_dir(vol->ad_path(src, 0 )));
- if (unix_rename( adsrc, ad_dir(vol->ad_path(dst, 0 ))) < 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->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;
{
/* We simply move the corresponding ad file as well */
char tempbuf[258]="._";
- return rename(vol->ad_path(oldpath,0),strcat(tempbuf,newpath));
+ return unix_rename(dirfd, vol->ad_path(oldpath,0), -1, strcat(tempbuf,newpath));
}
/* ---------------- */
strcpy( adsrc, vol->ad_path(src, 0 ));
- if (unix_rename( adsrc, vol->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;
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)
+#ifdef HAVE_ACLS
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)
+#endif
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_deletefile,
vfs_renamefile,
vfs_copyfile,
+#ifdef HAVE_ACLS
vfs_acl,
vfs_remove_acl,
+#endif
vfs_ea_getsize,
vfs_ea_getcontent,
vfs_ea_list,
/* vfs_setdirowner: */ RF_setdirowner_adouble,
/* vfs_deletefile: */ RF_deletefile_adouble,
/* vfs_renamefile: */ RF_renamefile_adouble,
+ /* vfs_copyfile: */ RF_copyfile_adouble,
NULL
};
/* vfs_setdirowner: */ RF_setdirowner_osx,
/* vfs_deletefile: */ RF_deletefile_adouble,
/* vfs_renamefile: */ RF_renamefile_osx,
+ /* vfs_copyfile: */ NULL,
NULL
};
/* vfs_setdirowner: */ RF_setdirowner_ads,
/* vfs_deletefile: */ RF_deletefile_ads,
/* vfs_renamefile: */ RF_renamefile_ads,
+ /* vfs_copyfile: */ NULL,
NULL
};
/* vfs_deletefile: */ ea_deletefile,
/* vfs_renamefile: */ ea_renamefile,
/* vfs_copyfile */ ea_copyfile,
+#ifdef HAVE_ACLS
/* vfs_acl: */ NULL,
/* vfs_remove_acl */ NULL,
+#endif
/* vfs_getsize */ get_easize,
/* vfs_getcontent */ get_eacontent,
/* vfs_list */ list_eas,
/* vfs_remove */ remove_ea
};
-static struct vfs_ops netatalk_ea_solaris = {
+static struct vfs_ops netatalk_ea_sys = {
/* validupath: */ NULL,
/* rf_chown: */ NULL,
/* rf_renamedir: */ NULL,
/* rf_setdirowner: */ NULL,
/* rf_deletefile: */ NULL,
/* rf_renamefile: */ NULL,
- /* vfs_copyfile: */ NULL,
+ /* vfs_copyfile: */ sys_ea_copyfile,
+#ifdef HAVE_ACLS
/* 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
+ /* 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
+#ifdef HAVE_SOLARIS_ACLS
static struct vfs_ops netatalk_solaris_acl_adouble = {
/* validupath: */ NULL,
/* rf_chown: */ NULL,
/* rf_renamefile: */ NULL,
/* vfs_copyfile */ NULL,
/* rf_acl: */ RF_solaris_acl,
- /* rf_remove_acl */ RF_remove_acl,
+ /* rf_remove_acl */ RF_solaris_remove_acl,
+ NULL
+};
+#endif
+
+#ifdef HAVE_POSIX_ACLS
+static struct vfs_ops netatalk_posix_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_posix_acl,
+ /* rf_remove_acl */ RF_posix_remove_acl,
NULL
};
#endif
}
/* Extended Attributes */
- if (vol->v_vfs_ea == AFPVOL_EA_SOLARIS) {
-
- LOG(log_debug, logtype_afpd, "initvol_vfs: Enabling EA support with native EAs.");
- vol->vfs_modules[1] = &netatalk_ea_solaris;
- } else {
- /* default: AFPVOL_EA_AD */
- LOG(log_debug, logtype_afpd, "initvol_vfs: Enabling EA support with adouble files.");
+ 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 {
+ LOG(log_debug, logtype_afpd, "initvol_vfs: volume without EA support");
}
/* ACLs */
-#ifdef HAVE_NFSv4_ACLS
+#ifdef HAVE_SOLARIS_ACLS
vol->vfs_modules[2] = &netatalk_solaris_acl_adouble;
#endif
+#ifdef HAVE_POSIX_ACLS
+ vol->vfs_modules[2] = &netatalk_posix_acl_adouble;
+#endif
+
}