]> arthur.barton.de Git - netatalk.git/commitdiff
EA VFS: FPCopyFile support
authorfranklahm <franklahm>
Thu, 15 Oct 2009 12:06:07 +0000 (12:06 +0000)
committerfranklahm <franklahm>
Thu, 15 Oct 2009 12:06:07 +0000 (12:06 +0000)
etc/afpd/file.c
etc/afpd/unix.c
include/atalk/Makefile.am
include/atalk/adouble.h
include/atalk/ea.h
include/atalk/unix.h [new file with mode: 0644]
include/atalk/vfs.h
libatalk/vfs/ea.c
libatalk/vfs/unix.c
libatalk/vfs/vfs.c

index db8fdfe76cb5541c7662bf41c68af763fc867f3a..e08a40682f1ef82aba8fb6e6529d47b36ca79933 100644 (file)
@@ -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 <atalk/afp.h>
 #include <atalk/util.h>
 #include <atalk/cnid.h>
+#include <atalk/unix.h>
+
 #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) {
index 5ab23eeafe453de2a3b1865b7bb9c628f6f699e1..0ffdd40e7813673742dae66acf0898d3faefca68 100644 (file)
@@ -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 <atalk/vfs.h>
 #include <atalk/afp.h>
 #include <atalk/util.h>
+#include <atalk/unix.h>
 
 #include "auth.h"
 #include "directory.h"
index 40d4121bd31114173bd16851d122b9e0453e8ec1..1fb4b50376fb7447d618f0a62f1b312d5cdd18e8 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 acl.h
+       zip.h ea.h acl.h unix.h
 
 noinst_HEADERS = cnid_dbd_private.h
index bc6bb196215e54b4eae45ac0e70a8f4bd6805a71..140ae32f2f7cec7533b2da370f0791bcb2644012 100644 (file)
@@ -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 */
index febf91fa5504acd510ff9bebec765c0d8d15beb4..c2add23b7100cbf564cc65745896dca170e31542 100644 (file)
@@ -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 <franklahm@gmail.com>
 
    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 (file)
index 0000000..af671ac
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+   $Id: unix.h,v 1.1 2009-10-15 12:06:07 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_UNIX_H
+#define ATALK_UNIX_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+
+/* 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 */
index 60495a14feab6a41fe0a6f876f3464fea541e0a1..dba6b231c8eb5a8824754791d7d7db5c174aeba2 100644 (file)
@@ -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);
index 6cfa6132d4e00531fec6b9ab432a843dc05c58a2..44188c0a8858dca4e88159e4234a696cd3ec8d35 100644 (file)
@@ -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 <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
@@ -39,6 +39,7 @@
 #include <atalk/volume.h>
 #include <atalk/vfs.h>
 #include <atalk/util.h>
+#include <atalk/unix.h>
 
 /*
  * 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;
+}
index 056bdf02f6147da6cca445f922efb197b02c3380..eaec6aab576d184eb0566d50dc4c3ae501338b83 100644 (file)
@@ -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 <atalk/directory.h>
 #include <atalk/volume.h>
 #include <atalk/logger.h>
+#include <atalk/unix.h>
 
 /* -----------------------------
    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;
+}
index b1532bc0e0271a02763f9705bf75a216b5480f98..81ececd3dab38943021fcc1ece4da84e83c2461b 100644 (file)
@@ -32,6 +32,7 @@
 #include <atalk/util.h>
 #include <atalk/volume.h>
 #include <atalk/directory.h>
+#include <atalk/unix.h>
 
 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
 };