From dbf558207127d21596b307d388a90df42d7a218e Mon Sep 17 00:00:00 2001 From: franklahm Date: Thu, 15 Oct 2009 12:06:07 +0000 Subject: [PATCH] EA VFS: FPCopyFile support --- etc/afpd/file.c | 14 +++++-- etc/afpd/unix.c | 3 +- include/atalk/Makefile.am | 2 +- include/atalk/adouble.h | 11 +---- include/atalk/ea.h | 3 +- include/atalk/unix.h | 35 ++++++++++++++++ include/atalk/vfs.h | 4 ++ libatalk/vfs/ea.c | 84 ++++++++++++++++++++++++++++++++++++++- libatalk/vfs/unix.c | 55 ++++++++++++++++++++++++- libatalk/vfs/vfs.c | 73 +++++++++++++++++++--------------- 10 files changed, 232 insertions(+), 52 deletions(-) create mode 100644 include/atalk/unix.h diff --git a/etc/afpd/file.c b/etc/afpd/file.c index db8fdfe7..e08a4068 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -1,5 +1,5 @@ /* - * $Id: file.c,v 1.114 2009-10-15 10:43:13 didg Exp $ + * $Id: file.c,v 1.115 2009-10-15 12:06:07 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -39,6 +39,8 @@ char *strchr (), *strrchr (); #include #include #include +#include + #include "directory.h" #include "desktop.h" #include "volume.h" @@ -1420,11 +1422,15 @@ int copyfile(const struct vol *s_vol, const struct vol*d_vol, } return AFPERR_EXIST; } - /* XXX if the source and the dest don't use the same resource type it's broken - */ + + /* + * XXX if the source and the dest don't use the same resource type it's broken + */ if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){ /* copy the data fork */ - err = copy_fork(ADEID_DFORK, &add, adp); + if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) { + err = d_vol->vfs->vfs_copyfile(d_vol, src, dst); + } } if (err < 0) { diff --git a/etc/afpd/unix.c b/etc/afpd/unix.c index 5ab23eea..0ffdd40e 100644 --- a/etc/afpd/unix.c +++ b/etc/afpd/unix.c @@ -1,5 +1,5 @@ /* - * $Id: unix.c,v 1.55 2009-10-14 15:04:01 franklahm Exp $ + * $Id: unix.c,v 1.56 2009-10-15 12:06:07 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -39,6 +39,7 @@ char *strchr (), *strrchr (); #include #include #include +#include #include "auth.h" #include "directory.h" diff --git a/include/atalk/Makefile.am b/include/atalk/Makefile.am index 40d4121b..1fb4b503 100644 --- a/include/atalk/Makefile.am +++ b/include/atalk/Makefile.am @@ -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 acl.h + zip.h ea.h acl.h unix.h noinst_HEADERS = cnid_dbd_private.h diff --git a/include/atalk/adouble.h b/include/atalk/adouble.h index bc6bb196..140ae32f 100644 --- a/include/atalk/adouble.h +++ b/include/atalk/adouble.h @@ -1,5 +1,5 @@ /* - * $Id: adouble.h,v 1.45 2009-10-14 01:38:28 didg Exp $ + * $Id: adouble.h,v 1.46 2009-10-15 12:06:07 franklahm Exp $ * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. * @@ -552,13 +552,4 @@ extern ssize_t ad_writefile (struct adouble *, const int, #endif /* HAVE_SENDFILE_WRITE */ #endif /* 0 */ -/* ad_unix.c */ -extern int netatalk_unlink(const char *name); -extern char *fullpathname(const char *); -extern int netatalk_rmdir(const char *name); -extern int setfilmode(const char *, mode_t, struct stat *, mode_t); -extern int dir_rx_set(mode_t mode); -extern int stickydirmode(const char *name, const mode_t mode, const int dropbox, const mode_t v_umask); -extern int unix_rename(const char *oldpath, const char *newpath); - #endif /* _ATALK_ADOUBLE_H */ diff --git a/include/atalk/ea.h b/include/atalk/ea.h index febf91fa..c2add23b 100644 --- a/include/atalk/ea.h +++ b/include/atalk/ea.h @@ -1,5 +1,5 @@ /* - $Id: ea.h,v 1.2 2009-10-14 15:04:01 franklahm Exp $ + $Id: ea.h,v 1.3 2009-10-15 12:06:07 franklahm Exp $ Copyright (c) 2009 Frank Lahm This program is free software; you can redistribute it and/or modify @@ -125,6 +125,7 @@ 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); +extern int ea_copyfile(VFS_FUNC_ARGS_COPYFILE); /* Solaris native EAs */ #ifdef HAVE_SOLARIS_EAS diff --git a/include/atalk/unix.h b/include/atalk/unix.h new file mode 100644 index 00000000..af671acf --- /dev/null +++ b/include/atalk/unix.h @@ -0,0 +1,35 @@ +/* + $Id: unix.h,v 1.1 2009-10-15 12:06:07 franklahm Exp $ + 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 + 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_UNIX_H +#define ATALK_UNIX_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +/* vfs/unix.c */ +extern int netatalk_unlink(const char *name); +extern char *fullpathname(const char *); +extern int netatalk_rmdir(const char *name); +extern int setfilmode(const char *, mode_t, struct stat *, mode_t); +extern int dir_rx_set(mode_t mode); +extern int stickydirmode(const char *name, const mode_t mode, const int dropbox, const mode_t v_umask); +extern int unix_rename(const char *oldpath, const char *newpath); +extern int copy_file(const char *src, const char *dst, mode_t mode); + +#endif /* ATALK_UNIX_H */ diff --git a/include/atalk/vfs.h b/include/atalk/vfs.h index 60495a14..dba6b231 100644 --- a/include/atalk/vfs.h +++ b/include/atalk/vfs.h @@ -58,6 +58,9 @@ #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_COPYFILE const struct vol *vol, const char *src, const char *dst +#define VFS_FUNC_VARS_COPYFILE 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 @@ -96,6 +99,7 @@ struct vfs_ops { int (*vfs_setdirowner) (VFS_FUNC_ARGS_SETDIROWNER); int (*vfs_deletefile) (VFS_FUNC_ARGS_DELETEFILE); int (*vfs_renamefile) (VFS_FUNC_ARGS_RENAMEFILE); + int (*vfs_copyfile) (VFS_FUNC_ARGS_COPYFILE); /* ACLs */ int (*vfs_acl) (VFS_FUNC_ARGS_ACL); diff --git a/libatalk/vfs/ea.c b/libatalk/vfs/ea.c index 6cfa6132..44188c0a 100644 --- a/libatalk/vfs/ea.c +++ b/libatalk/vfs/ea.c @@ -1,5 +1,5 @@ /* - $Id: ea.c,v 1.3 2009-10-14 15:04:01 franklahm Exp $ + $Id: ea.c,v 1.4 2009-10-15 12:06:07 franklahm Exp $ Copyright (c) 2009 Frank Lahm This program is free software; you can redistribute it and/or modify @@ -39,6 +39,7 @@ #include #include #include +#include /* * Store Extended Attributes inside .AppleDouble folders as follows: @@ -1661,3 +1662,84 @@ exit: ea_close(&dstea); return ret; } + +int ea_copyfile(VFS_FUNC_ARGS_COPYFILE) +{ + 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_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_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() */ + eapath = ea_path(&srcea, eaname); + strcpy(srceapath, eapath); + eapath = ea_path(&dstea, eaname); + + 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( 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; +} diff --git a/libatalk/vfs/unix.c b/libatalk/vfs/unix.c index 056bdf02..eaec6aab 100644 --- a/libatalk/vfs/unix.c +++ b/libatalk/vfs/unix.c @@ -1,5 +1,5 @@ /* - * $Id: unix.c,v 1.1 2009-10-02 09:32:41 franklahm Exp $ + * $Id: unix.c,v 1.2 2009-10-15 12:06:08 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -22,6 +22,7 @@ #include #include #include +#include /* ----------------------------- a dropbox is a folder where w is set but not r eg: @@ -153,3 +154,55 @@ char *fullpathname(const char *name) } return wd; } + +int copy_file(const char *src, const char *dst, mode_t mode) +{ + int ret = 0; + int sfd = -1; + int dfd = -1; + size_t cc; + char filebuf[8192]; + + if ((sfd = open(src, O_RDONLY)) < 0) { + LOG(log_error, logtype_afpd, "copy_file('%s'/'%s'): open '%s' error: %s", + src, dst, src, strerror(errno)); + return -1; + } + + if ((dfd = open(dst, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) { + LOG(log_error, logtype_afpd, "copy_file('%s'/'%s'): open '%s' error: %s", + src, dst, dst, strerror(errno)); + ret = -1; + goto exit; + } + + while ((cc = read(sfd, filebuf, sizeof(filebuf)))) { + if (cc < 0) { + if (errno == EINTR) + continue; + LOG(log_error, logtype_afpd, "copy_file('%s'/'%s'): read '%s' error: %s", + src, dst, src, strerror(errno)); + ret = -1; + goto exit; + } + + while (cc > 0) { + if ((cc -= write(dfd, filebuf, cc)) < 0) { + if (errno == EINTR) + continue; + LOG(log_error, logtype_afpd, "copy_file('%s'/'%s'): read '%s' error: %s", + src, dst, dst, strerror(errno)); + ret = -1; + goto exit; + } + } + } + +exit: + if (sfd != -1) + close(sfd); + if (dfd != -1) + close(dfd); + + return ret; +} diff --git a/libatalk/vfs/vfs.c b/libatalk/vfs/vfs.c index b1532bc0..81ececd3 100644 --- a/libatalk/vfs/vfs.c +++ b/libatalk/vfs/vfs.c @@ -32,6 +32,7 @@ #include #include #include +#include struct perm { uid_t uid; @@ -809,6 +810,7 @@ VFS_MFUNC(setdirunixmode, VFS_FUNC_ARGS_SETDIRUNIXMODE, VFS_FUNC_VARS_SETDIRUNIX 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) @@ -843,6 +845,7 @@ struct vfs_ops vfs_master_funcs = { vfs_setdirowner, vfs_deletefile, vfs_renamefile, + vfs_copyfile, vfs_acl, vfs_remove_acl, vfs_ea_getsize, @@ -857,46 +860,47 @@ struct vfs_ops vfs_master_funcs = { */ static 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, + /* vfs_path: */ ad_path, + /* 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 + /* NULL, ... */ }; static 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, + /* vfs_path: */ ad_path_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 }; /* samba sfm format. ad_path shouldn't be set her */ static 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, + /* vfs_path: */ ad_path_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, }; /* @@ -915,6 +919,7 @@ struct vfs_ops netatalk_ea_adouble = { /* rf_setdirowner: */ NULL, /* rf_deletefile: */ ea_deletefile, /* rf_renamefile: */ ea_renamefile, + /* vfs_copyfile */ ea_copyfile, /* rf_acl: */ NULL, /* rf_remove_acl */ NULL, /* ea_getsize */ get_easize, @@ -937,6 +942,7 @@ struct vfs_ops netatalk_ea_solaris = { /* rf_setdirowner: */ NULL, /* rf_deletefile: */ NULL, /* rf_renamefile: */ NULL, + /* vfs_copyfile: */ NULL, /* rf_acl: */ NULL, /* rf_remove_acl */ NULL, /* ea_getsize */ sol_get_easize, @@ -964,6 +970,7 @@ struct vfs_ops netatalk_solaris_acl_adouble = { /* rf_setdirowner: */ NULL, /* rf_deletefile: */ NULL, /* rf_renamefile: */ NULL, + /* vfs_copyfile */ NULL, /* rf_acl: */ RF_solaris_acl, /* rf_remove_acl */ RF_remove_acl }; -- 2.39.2